Teach-In 2008 Using PIC Microcontrollers Part One – Introduction to PIC Microcontrollers and the Development Interface Board for this series JOHN BECKER
T
EACH-IN 2008 takes a slightly different format to previous Teach-Ins. Whereas the earlier ones have concentrated on telling you about components and how to use them in general, Teach-In 2008 takes a specific component, a PIC microcontroller, the PIC16F628, and examines it in detail, providing you with information on how to use PICs in your own projects. The series has been inspired by the number of readers, many of them new to reading EPE, who have been noting the emphasis we place on PICs and who wish to know more about how to use them. In the past, we have published PIC Tutorials in various forms, and the last one, EPE PIC Tutorial V2, is still valid. That concentrated on a command-bycommand examination and explanation of various aspects of PIC programming, principally in relation to the PIC16F84. The text, hardware and softare for it are on our PIC Resources CD-ROM, periodically advertised in our pages.
Constructional examples This Teach-In 2008 gives constructional examples in each part of the series, explaining how to program and use a PIC16F628 in a variety of circuit types, using ‘breadboarded’ circuits you can quickly and easily put together yourself. They could also be assembled on stripboard, for a more permanent construction, although guidance on stripboard assembly is not given.
Prototype of the dual-purpose PIC programming and development interface board used in the Teach-In 2008 series
can be readily used to write programs for other PICs from the increasing number of types available. Most of the commands used are similar between types, although the method in which they are used can vary between PIC families.
PIC16F628
Getting started
The PIC16F628 was chosen because it is a good compromise between the various PIC types available and simplicity of use. There are many PICs in the current range which are totally unsuited to learning about PICs in general, requiring too many concepts to be grasped by the newcomer to PICs. The PIC16F628 is one of the 16F family but without a lot of the ‘frills’ now found in many PIC families. There are other 16Fs that could have been chosen, but this one is widely available from many suppliers. For this series, the PIC16F627 could also be used without changes, the only difference is that it has a somewhat smaller memory capacity. Once you understand the basics of programming a PIC16F628, your knowledge
In this first part of the series we tell you about the general nature of a PIC microcontroller, and present a simple PIC programming circuit which is assembled on a small printed circuit board (PCB). Its controlling software is the author’s renowned Toolkit TK3 assembler/programmer. This provides the essential aspects required for writing and assembling PIC software, and programming the PIC with the results via a PC’s parallel printer port. There are many text notes built into the TK3 program that give information on how use it. The board is also used as the Master Control PCB for the Teach In 2008 demonstration programs. It will also be of future use when writing your own software.
20
It is recognised that many modern PCs do not have a parallel printer port, and use a USB serial bus. For those readers who cannot use the programming aspects of the Master Control PCB to program their PICs, it is recommended that a simple PIC Programmer such as the PICkit2 programmer be used, as reviewed by Mike Hibbett in the July ’07 issue. PICkit2 can be used to actually program your PIC, and then the PIC can be transferred to the Master Control PCB for use in the demo program examples presented in this series. The Master Control PCB is described later, along with its assembly. Details of obtaining the PICkit2 hardware and software are also given later. If you already have the PCB designed to go with the TK3 software when it was originally published, then you may use that instead of the Master Control PCB. The same applies to the TK3 board available pre-built from Magenta Electronics. The TK3 boards have facilities for programming a variety of PIC sizes.
Everyday Practical Electronics, November 2007
Origin When the original EPE PIC Tutorial was published in March to May 1998, letters and phone calls to EPE had demonstrated that interest in Microchip’s PIC microcontrollers had become intense. Many readers were asking for more information on how to use these devices in designs of their own invention. In the words of one reader, “Please show me how to get to grips with the essence of PICs. Tell me, step-by-step, how to get started with writing simple programs, how to just turn on a single light emitting diode, for example. Then take me forward from there”. This Teach In 2008 first takes the general concept of using a PIC to turn an LED on and off, and then progresses to show how this concept, and others which follow during the series, can be used in practical situations. At various stages of the series, additional commands and concepts are introduced as part of the demos, and they are explained in turn. By the end of the series you will have a good grasp of all the commands available, and of how to implement the concepts presented in your own designs. Many thousands of readers have already learned to do this via the PIC Tutorials previously published. We assume in this series that you have no previous knowledge of PICs and their programming, although you may find it useful if you know a bit about digital logic, but this is not essential. It is important that you have had some experience of electronic component assembly when it comes to copying and using the breadboard layouts, along with assembling the Master Control PCB.
What is a PIC? It’s worth explaining briefly what a PIC chip is, before we move ahead. A PIC chip, in this context, is a microcontroller integrated circuit manufactured by Microchip. When asked about the name’s origin, Microchip’s Technical Department replied, “PIC is not an acronym; it is just a trademarked name that General Instruments came up with a long time ago”. (GI were the originators of PICs.) A microcontroller is similar to a microprocessor, but it additionally contains its own program command code memory, data storage memory, bi-directional (input/output) ports and a clock oscillator. Many microprocessors require the use of additional chips to provide these requirements; microcontrollers are totally selfcontained, although they usually need an external clock source, such as a crystal (but not the PIC16F628, which has its own internal source). The great advantage of microcontrollers is that they can be programmed to perform many functions for which many other chips would normally be required. This not only makes for simplicity in electronic designs, but also allows some functions to be performed which could not be done using normal digital logic chips – ie circuits for which a microprocessor and peripheral devices would be required. There are many types of microcontroller manufactured by various companies, including the AVR family from Atmel, but
for at least 10 years EPE has largely standardised on PICs, and many readers appreciate this emphasis. Microchip are recognised as one of the largest manufacturers of microcontrollers. PICs are manufactured and supplied ‘empty’. That is, they are without program codes (commands) and cannot control a circuit until they have been provided with a program that tells them what to do. It is the task of the program writer (you) to tell them what that is. The commands are written in a specialised form of English, largely consisting of mnemonics, known as the ‘source code’. There are several methods by which the souce code can be written, such as assembler, ‘C’ in numerous forms, and varieties of Basic. It is assembler we use here. It is a very simple programming dialect, and utilises Micropchip’s own commands without the sophistication of higher level dialects such as ‘C’. (Discussion of the use of flowcharts is beyond the scope of this series.) An assembly program (such as that supplied for this series, and the PICkit2 system referred to earlier) then translates (assembles or compiles) the source code commands into a numerical form that the PIC can understand – the ‘program code’. This code, which is normally stored on a file in hexadecimal, is then sent (loaded) in binary format to the PIC by electronic hardware, such as the PCB described later.
Inside the 16F628 The pinouts for the PIC16F628 are shown in Fig.1.1 It is an EEPROM (electrically erasable programmable read only memory) device, but perhaps more correctly described as a ‘flash’ device, hence the ‘F’ in its type number. This means that it can be rapidly reprogrammed as often as you wish (within the limits stated by Microchip – but these run into many thousands of reprogramming cycles and should not normally concern you). Note that there are several sub-versions of individual PIC types, having suffixes such as -04, -10 and -20. The suffix indicates the maximum clock rate at which the chip can be used: 4MHz, 10MHz and
Fig.1.1 Pinouts for the PIC16F628
20MHz respectively. You may use any device speed rating for this Teach-In series. The PIC16F628 used here has two input/output (I/O) ports, Port A and Port B. Port A basically has five pins (RA0 to RA4), and Port B has eight pins (RB0 to RB7). Port A does have three other pins,
Everyday Practical Electronics, November 2007
which may be used for I/O, but their use as I/O depends on some other functional choices of pin use, and that aspect is best ignored at this stage. The PIC16F628 has several oscillator modes, ranging from an internal 4MHz clock or external crystal control at different speed ratings, through to various forms of resistance control. It is only the first that will be used in this series. The PIC’s datasheet gives details of other oscillator types if you wish to know more once this series has ended.
Keying-in PIC source code You must be able to use a word-processing program (text editor) in order to write your own PIC source code. This must produce a text file that is totally without formatting and printer commands. That is, it must be able to generate a pure ASCII text file (and to input one). The TK3 assembly/programming software available for this series and the Master Control PCB, allows access to a choice of text editors, ranging from DOS Edit to NotePad. You may also provide your own links to your own preferred text editor if you wish.
Personal ability Throughout this series we shall examine the 35 basic PIC commands in a fair amount of detail. It is hoped that this will give you all the necessary information to enable you to conceive a design in which you can use a PIC16F628 to control whatever situation you wish, and to write the code that will let it do so. There is, though, much more to writing PIC programs than you may at this stage fully appreciate. Knowledge about individual commands and the way in which they can be used is not enough in itself. Programming is a way of looking at the world in ways that other people may not recognise. You must have the mental ability to see each programming situation as a step-bystep function, visualising and analysing in your mind exactly how it is that you need to specify the complete program flow. You have to write the sequence of events with the correct grammar, with the correct spelling and in the correct order. Undoubtedly, you will make mistakes while you are writing the code, failing to see the correct sequence of events and using incorrect command structures. You require the ability to analyse what you have done wrong and to correct it. You are likely to be confronted with an overall task that may, on occasion, take you into several days or even weeks of dedicated concentration. Readers have occasionally asked how they can be taught to think like a programmer. There is no easy way in which this can be taught. Some people have the ability, some do not. The best way to learn is by actually writing snippets of code and getting those to work, giving you the experience and confidence to progress to more complex situations. Programming, to those who have the ability to see things ‘as they are’ and not ‘how they seem to be’, can become extremely addictive. You could find yourself compelled to get back to the keyboard
21
and PIC programmer at any conceivable hour. You had better have an understanding family! Readers who have had experience of programming in one of the general dialects of Basic, or with other types of microprocessor or microcontroller, will find that once a few commands have had their functions explained, using them will rapidly become instinctive. Other readers without such experience will, it has to be said, have to become accustomed to understanding programming itself as a step-by-step process. An analytical mind is required and, as said earlier, there is no easy way in which programming can be taught to those who lack experience.
Master Control Board
MASTER CONTROL – DEVELOPMENT INTERFACE CIRCUIT
The circuit diagram for the Master Control board is shown in Fig.1.2. It is based on the circuit used by the author for the TK3 board referred to earlier. It will not be discussed in depth. Details of the TK3 board are available on the PIC Resources CD ROM, also referred to earlier. The circuit can be run from a 9V to 12V DC power source, such as a battery or plugpack which plugs into household mains sockets. IC4 regulates the input voltage down to +5V, as required by the PIC and other ICs. IC1 boosts the +5V to around +14V to provide the programming voltage required by the PIC, and returning that voltage to +5V at the end of programming procedures.
Fig. 1.2. Circuit diagram of the dual-purpose PIC programming and development interface (Master Control Board)
22
Everyday Practical Electronics, November 2007
MASTER CONTROL BOARD
Fig.1.3. Assembly and track layout details for the circuit in Fig.1.2.
Everyday Practical Electronics, November 2007
23
Programming control signals are provided by the parallel port of a PC (see earlier). The input signals, and those fed back to the PC during programming, are routed via IC5 and IC3 to the PIC, IC2. PIC reset control is supplied by the PC and transistor TR1. Pushswitch S1 allows manual control of resetting when desired. The connections at TB1 are those to and from the in-situ PIC’s Port A and Port B I/O pins. Additional connections to Port B are provided for eight on-board LEDs. There is a link wire provided in the common cathode line, following buffer resistors R14 to R21, to connect the cathodes to 0V, so allowing the LEDs to be brought into service when required, and without affecting the Port B I/Os when they are not. Link B may be used to reverse bias the LEDs if you wish to do so when they are not in use. Never link both links. Additional connections (TB1) are provided on the PCB for connecting an alphanumeric liquid crystal display (LCD). Details for the LCD will be shown in a future part when its use will be discussed. Also provided is a 4-pin connector point (TB2) through which other PICs on other boards can be programmed.
Master Control PCB assembly Details of the track and component layouts for the PCB are shown in Fig.1.3. This board is available from the EPE PCB Service, code 647. Note that the board has pin connections which can plug into a 0.1in pitch breadboard, as a convenient securing facility. A breadboard will be used throughout the series for assembling a few components for the various demonstrations. Assemble the PCB in order of ascending component size, starting with the link wires, noting that some go under IC positions. Do not connect the link A or B wires to the right of the PCB – their use will be discussed with regard to LED usage in a future part. Observe the correct orientation for all polarity sensitive components, including semiconductors and electrolytic capacitors. Dual-in-line (DIL) IC sockets should be used for all ICs. The socket used for the PIC may be a zero insertion force (ZIF) socket for future convenience. When mounting socket SK1, securely bolt it to the PC before its connections are soldered. Facilities for checking the assembled board functionally are provided by the TK3 software, but do not insert any DIL ICs until the correctness of the voltage output by regulator IC4 has been proved to be +5V, within a few millivolts.
PC and PIC software The TK3 software for controlling the Master Control PCB, is available for free download from the EPE Downloads site, access via www.epemag.co.uk. Simply save the zip file onto your PC and unzip the enclosed files into their named folder. They may be copied to a seperate folder having a name of your choice. Do not attempt to ‘install’ any of the software via Internet Explorer or similar, use Window’s own copying facility. The PC software has been proved on Window’s platforms up to and including
24
Parts List – Teach-In 2008 – Master Control PCB 1
PC board, code 647, available from the EPE PCB Service, size 112mm × 94mm
1
BC549 NPN transistor (TR1)
1
MAX662A voltage converter (IC1)
1
36-way Centronics parallel port connector, female (SK1)
1
PIC16F628 PIC micrcontroller (IC2)
1
3.2768MHz crystal (see text) (X1) (optional)
1
1
9V DC power source, eg PP9 battery (see text)
4053 3-pole 2-way analogue changeover switch/multiplexer (IC3)
1
1
single-pole, PC mounting ‘clickeffect’ pushbutton switch, pushto-make (S1)
78L05 +5V 100mA voltage regulator (IC4)
1
4050 Hex buffer, non-inverting (IC5)
1
10kΩ minature round preset potentiometer, PC mounting
1
8-pin DIL socket
Capacitors 2 10pF ceramic disc, 0.2in pitch (C7,C8)
2
16-pin DIL sockets
2
1
18-pin DIL socket
100nF ceramic disc, 0.2in pitch (C4,C6)
2
4-pin DIL 1mm pin-header strips (TB1 and TB2)
2
220nF ceramic disc, 0.2in pitch (C1,C2)
1
6-pin DIL 1mm pin-header strip (TB1)
2
4μ7 radial elect. 63V (C3, C5)
31 1mm terminal solder pins 4
PCB supports, self-adhesive
Semiconductors 9 5mm red LEDs (D1 to D9)
Resistors (0.25W 5% carbon) 8 470Ω (R14 to R21) 8 1k (R5 to R11, R13) 1 10k (R12) 4 100k (R1 to R4)
Fig.1.4. Main control screen of the TK3 Programmer XP, where such PCs have a parallel printer port included. The main control screen in shown in Fig.1.4. There are numerous on-screen Notes click-buttons, which give access to various details about the PC sofware’s use. It is not discussed here.
Basic PIC16F628 facts All the commands for the PIC16F628 are shown in Table 1. Most of them apply to other PIC families too, though some
families also have additional commands available. There are also some Special Register Files (SFRs) that are frequently used in PIC programs. Part of the PIC16F628’s memory map is shown in Table 1.2. You normally work in Bank 0, but SFRs are held in other Banks, and you also have acess to additional memory in some others too. Again, note that other PIC families may have somewhat different arrangements.
Everyday Practical Electronics, November 2007
Table 1.2 PIC16F628 Memory Map For The First Two Banks. (Microchip datasheet)
Table 1.1. PIC Command Codes For PIC16F62x
Command /Syntax
Flags Cycles Description affected
BYTE-ORIENTATED FILE REGISTER OPERATIONS ADDWF f,d ANDWF f,d CLRF f CLRW COMF f,d DECF f,d DECFSZ f,d INCF f,d INCFSZ f,d IORWF f,d MOVF f,d MOVWF f NOP RLF f,d RRF f,d SUBWF f,d SWAPF f,d XORWF f,d
C, DC, Z 1 Z 1 Z 1 Z 1 Z 1 Z 1 1 (2) Z 1 1 (2) Z 1 Z 1 1 1 C 1 C 1 C, DC, Z 1 1 Z 1
Add W and f AND W with f Clear f Clear W Complement f Decrement f Decrement f, skip if 0 Increment f Increment f, skip if 0 Inclusive OR W with f Move f Move W to f No operation Rotate left f through Carry Rotate right f through Carry Subtract W from f Swap nibbles in f Exclusive OR W with f
BIT-ORIENTATED REGISTER OPERATIONS BCF f,b 1 Bit clear f BSF f,b 1 Bit set f BTFSC f,b 1 (2) Bit test f, skip if 0 BTFSS f,b 1 (2) Bit test f, skip if 1 LITERAL AND ADDLW k ANDLW k CALL k CLRWDT GOTO k IORLW k MOVLW k RETFIE – RETLW k RETURN SLEEP SUBLW k XORLW k
CONTROL OPERATIONS C, DC, Z 1 Add literal and W Z 1 AND literal with W 2 Call subroutine TO, PD 1 Clear Watchdog Timer 2 Go to address Z 1 Inclusive OR literal with W 1 Move literal to W 2 Return from interrupt 2 Return with literal in W 2 Return from subroutine TO, PD 1 Go into standby mode C, DC, Z 1 Subtract W from literal Z 1 Exclusive OR literal with W
The full datasheets for various PICs can be downloaded free of charge from Microchip’s website at www.microchip.com. Before we start to look at programming PICs next month, there are a few facts to remember first.
Floating PIC pins It is worth noting that PIC pins should never be left as ‘floating’ inputs. If any PIC pins remain unused in a PIC-controlled circuit, they should either be biased to one or other power line by individual resistors (say 10k to 100k), or set as outputs in a logic 0 (low) condition.
Case sensitivity With some programmers (but not TK3), the names used in software are ‘case-sensitive’. In other words, once you have allocated a name to a register, further use of the name must be in exactly the same style as the original with regard to the use of upper and lower case letters. For example, names STORE1 and store1 cannot be used interchangeably. However, the commands themselves (as opposed to the names) may be in upper or lower case without (usually) causing
Teach-In 2008 Demos Parts 2 to 6 – You will Need 1
standard plug-in ‘breadboard’, 64 holes long by 14 holes wide, 1mm pitch 1 2-line 16-characters (per line) standard alphanumeric LCD 12 single-pole, PC mounting pushbutton switches, push-to-make 1 personal earpiece or miniature 40 ohm (approx) loudspeaker 1 10kΩ miniature round preset potentiometer, PC mounting Semiconductors 14 5mm red LEDs 2 1N4148 signal diodes 1 BC549 NPN transistor Resistors (0.2W 5% carbon) 7 470Ω 1 4k7 1 1k 4 10k Some additional parts may be needed as the series progresses
Everyday Practical Electronics, November 2007
25
problems. For example, in the Teach In 2008 demo programs, the commands are usually shown in lower case, although they could have been in upper case.
True and false In any logic question, there can only be one of two answers, either ‘yes’ or ‘no’ (you can never answer ‘maybe’ to such questions). In programming (and digital electronics too) if the answer is ‘yes’, then the answer is said to be ‘true’. If the answer is ‘no’, then the answer is said to be ‘false’ (not true). The convention is that if a situation is ‘true’ then it is represented by logic 1, Conversely, if the situation is ‘false’ it is represented by logic 0. Logic 1 and logic 0 are, of course, the two states in which a binary bit can be.
Set and clear The concepts of the terms ‘set’ and ‘clear’, as frequently used in programming, are important to understand. In program terms, to ‘set’ a bit means to force it high, ie to logic 1; the term ‘clear’ is used to mean that a bit is forced low, ie to logic 0. Note, however, that in textual terms (ie in articles such as this) you are likely to come across the mixed use of the word ‘set’, in that you might be told to ‘set a bit low’.
In such cases, the implied meaning should be obvious from the context. In this example, ‘low’ is the important word and ‘force’ or ‘make’ could have been used instead of ‘set’.
STATUS register Table 1.3 shows the arrange of the STATUS register, which is used for several purposes, depending on how its bits are set or cleared. Bit 0 is the bit which indicates whether a Carry or a Borrow has occurred during some commands. It is, incidentally, common to refer to such bits as being ‘flags’: the flag is then said to be set or cleared by any action which affects it. The Carry bit is referred to as bit C. Bit 1 is the Zero flag (Z bit), and indicates whether actioning a command has resulted in a value of 0 (Z = 0), or greater than 0 (Z = 1). Other bits will be discussed as we progress.
F and W statements in commands Data can be routed either to files or retained in the working register. A single code, either W or F, determines which destination is to be used. This code is required following the comma used with some commands.
For example, take the commands INCF PORTB,F and INCF PORTB,W. With the former, the value already held in PORTB is incremented and retained in PORTB, as instructed by the F. With the latter, the value already held in PORTB is incremented but retained in the working register, as instructed by the W, so no change is made to PORTB itself.
Program counter Microcontrollers such as PICs keep track of which program byte number is currently being processed, and there is a counter which holds this information – the Program Counter (PCL, as it is named for the PIC, Program Counter Low). Unless told otherwise, when one instruction has been performed, the program counter is automatically incremented (a value of 1 added to it) and the next consecutive command is performed. The program address number held by the PCL can be changed, either when the instruction is one such as GOTO or CALL, or by the user telling it to add another literal value to itself. The next instruction performed is that at the address pointed to by the new value. It will be seen, then, that if the value of 0 is added to the PCL, the next instruction is simply the next one on. If, however, the value of 1 is added to the PCL, then the
Table 1.3: Status Register (Microchip datasheet)
26
Everyday Practical Electronics, November 2007
next consecutive instruction is bypassed (skipped) and the one beyond it is performed instead. For example, if the program counter is at 52, then normally it will automatically add one to itself and the next instruction will be that at 53, and the one after that will be at 54, etc. If, somehow, we intervene and add 1 to the counter while it’s still 52, then the counter will become 53 but will still add its own value of 1 to itself, making 54. The program will thus jump straight from 52 to 54, omitting the instruction at 53. Should the value of 0 be added, then, of course, the program will go straight from 52 to 53.
Table 1.4: Program Memory Map And Stack For The PIC16F628
Opening ORG commands In the opening statements of a PIC progam, position ORG 0 is known as the reset vector (see Table 1.4). It is to this address that the PIC jumps when it is first run or subsequently reset. The command which follows it is then performed. Position ORG 4 is known as the interrupt vector. It is to this address that the
PIC program jumps if an interrupt occurs, then actioning the next command, whatever that may be, and there are several commands that could used. The subject of interrupts will be dealt with later. Ignore the concept for the moment. Position ORG 5 is the start of program vector, ie it indicates the first available position within the PIC at which the actual program can start. You will notice that locations 1, 2 and 3 are not mentioned. These are reserved by the PIC and are not available for normal program use. Having included the essential first few commands, everything else beyond ORG 5 is up to you.
Next month In Part Two next month, we will start to describe how to program PICs by detailing the coding for a simple demonstration program that shows how just a single LED can be turned on or off, and then progress from there.
Get your magazine ‘instantly’ anywhere in the world – buy and download from the web. TAKE A LOOK, A FREE ISSUE IS AVAILABLE A one year subscription (12 issues) costs just $18.99 (US) Back issues are also available
Everyday Practical Electronics, November 2007
27
Teach-In 2008 Using PIC Microcontrollers Part Two – Programme Basic Commands Plus Simple LED Control JOHN BECKER
T
his month we start off by describing a simple demonstration program that shows how just a single LED can be turned on or off. Such actions can be useful in larger programs to indicate an occurence of an event or action in the software, either for cosmetic reasons, or for testing purposes when writing programs. We also describe a ‘rotating’ display of eight LEDs. We then go on to describe a slightly more sophisticated program that can be used as a gaming dice, with LEDs to represent the spots on its surface. In the program discussed, the dice LEDs do not necessarily turn on in the order we expect them to in a conventional dice, however this will be remedied in the program discussed in Part 3.
Listing 2.1 ; TEACHINB01.ASM 07JUN07 - TEACH IN 2008 PT2 ; turn on individual LEDs seperately include p16f628.inc __config $3F30 CBLOCK h’20’ CLKCNT ENDC ORG 0 goto STARTIT ORG 4 goto STARTIT ORG 5 STARTIT
Single LED control This part’s first circuit diagram for control of LEDs, is shown on the right hand side of Fig.1.2, from last month, comprising just LEDs D2 to D9 and their ballast resistors R14 to R21. The breadboard is not needed yet. Just connect LINK A as shown in Fig.1.3 last month on the Master Control PCB to allow the eight LEDs to be activated. (Ensure that LINK B is not connected.) Let’s examine the program commands that cause the LED display to be shown. The program listing is shown in Listing 2.1. In Listing 2.1, the first things to notice are lines 1 and 2:
The next line is: include p16f628.inc
26
; reset vector ; Interrupt vector address ; PIC program memory start location
bsf STATUS,5 movlw b’00000000’ movwf TRISB movlw b’10000111’ movwf OPTION_REG bcf STATUS,5 call DELAY bsf PORTB,0 call DELAY bsf PORTB,1 call DELAY bsf PORTB,2 call DELAY bsf PORTB,3 call DELAY bsf PORTB,4 call DELAY bsf PORTB,5 call DELAY bsf PORTB,6 call DELAY bsf PORTB,7
; TEACHINB01.ASM 07JUN07 TEACH IN 2008 PT2 ; turn on individual LEDs seperately These lines describe the function of the program for the sake of the software writer, and anyone else who examines it. They are preceded by a semicolon (;). Any statement preceded by a semicolon, is ignored by the PIC programming software when assembling the code, and allows the software writer to place helpful comments against lines of program code, or elsewhere, so that their purpose is clear.
; internal 4MHz oscillator
; all PORTB as output ; data direction register for PORTB ; timer 1:256, pull-ups off (bit 7 =1)
; turn on LED at RB0 ; turn on LED at RB1 ; turn on LED at RB2 ; turn on LED at RB3 ; turn on LED at RB4 ; turn on LED at RB5 ; turn on LED at RB6 ; turn on LED at RB7
PROGEND nop goto PROGEND DELAY
movlw 25 movwf CLKCNT clrf INTCON
DELAY2 btfss INTCON,2 goto DELAY2 bcf INTCON,2 decfsz CLKCNT,F goto DELAY2 return
; set delay counter to 25 ; (for 1/25th sec x 5) ; clear interrupt flag ; ; has a timer time-out been detected? ; no ; yes ; dec counter, is it zero? ; no ; yes
END
Everyday Practical Electronics, December 2007
This indicates to the assembly program that it is to include (import) a file named p16F628.inc at this point. Such include files can have many functions, and are particularly useful when chunks of code are ‘library’ code that can be used in many programs without change. They save having to rewrite the same code each time it is needed. It is common for code sections to be repeated in many programs, and using include files is one way in which it can be done. Simply copying and pasting a section is another method. In this instance, the file is one provided by Microchip and specifies the many Special Function Registers (SFRs) that are used by the PIC named (PIC16F628 in this case). There are equivalent Microchip .inc files for all PICs, some of which are provided with the control software described last month. (They can also be downloaded from Microship’s website.) It is, of course, possible to also specify the same SFRs and their addresses as part of the program, but the use of the correct .inc file saves that task. You may examine the file’s contents through a text editor, but do not change it in any way. It is worth noting that include files such as this do not take up any PIC memory. They are simply used by the assembly program. Examples of how you would code in (equate) SFRs and user registers are shown later in the series.
PIC configuration
They may be expressed in decimal (e.g. 0, 4, 5) (which can also be specified in the form of D’xx’ – where ‘xx’ is any decimal value between 0 and 255). Hexadecimal format may also be used (indicated by a prefix of H), in the form H’00’ and h’7F’ for example. The range is normally h’00’ to h’FF’ (0 to 255), but it is possible to use double-byte values between 0 and 65525, with the range h’0000’ to h’FFFF’. Note that H’ or h’ are normally used, though this may depend on the assembler software you are using. Binary is the third format, prefixed by b’ and terminated by an apostrophe (’), in the form and range b’00000000’ to b’11111111’ (0 TO 255).
ORG and GOTO statements The next five program lines involve ORG and GOTO statements: ORG 0 ; reset vector goto STARTIT ORG 4 ; Interrupt vector address goto STARTIT ORG 5 ; PIC program memory start location At this stage they need not concern you, but they will be discussed later. Note, however, that no additional commands (other than Table statements which are discussed in a future part), may be added to the code before the next line (or its equivalent in another program): STARTIT.
Next comes the line: __config oscillator
$3F30
; internal 4MHz
An important concept to understand is that all PICs must be ‘configured’ for the application they are intended to control. Such configuration includes the selection of oscillator type, and matters such as Watchdog timer and Code Protection bits use (which are discussed in a future part). Once the configuration has been set it is not normally necessary to change it for the same application (and it is difficult to do so without special techniques). In this case, the configuration (Config) code simply tells the PIC when it is being programmed by the software to use its internal 4MHz oscilator to control the rate at which the commands are processed when the program in run. Be aware that the Config codes for various PIC functions vary widely between PICs. See the datasheet for the PIC in question (available via www. microchip.com). The control software described last month allows the Config codes to be set/shown for a small variety of PICs, including the PIC16F628. For the sake of Teach In 2008 you do not actually need to know the Config codes for the various demo programs, as they all have that information embedded into them as part of the PIC programming software.
Numerical formats In this instance, the Config code is quoted in the hexadecimal format. There are three main formats that can be used to express numerical values in a program.
STATUS register PICs are ‘told’ in manufacture to adopt certain ‘default’ conditions when first switched on. One of these default conditions is that PORTA and PORTB are configured (set) to act as inputs. When in an input condition they are simply held in a high impedance state (floating), and so could be adversely affected by stray electrical fields (the default conditions for all PIC registers are shown in the datasheet). The demonstration program in Listing 2.1 needs PORTB to be capable of outputting any value bewween 0 and 255 (an 8-bit byte). The STATUS register is that which is used to set the PIC’s data direction bits (among other things). Its table of functions was shown in Part 1, Table 1.3. After STARTIT (such sub-program identity statements are known as Labels), come the lines: bsf STATUS,5 movlw b’00000000’ ; all PORTB as output movwf TRISB ; data direction register for PORTB movlw b’10000111’ ; timer 1:256, pull-ups off (bit 7=1) movwf OPTION_REG bcf STATUS,5 If you examine a PIC’s datasheet, you will see that its user-memory is split into various sections, generally known as Banks. Part of an example memory map was in Table 1.2 of Part 1. The PIC has to be told which Bank it has to use and in which order to access certain SFRs within it. The SFRs which set the port data direction registers
Everyday Practical Electronics, December 2007
(DDRs) are in Bank 1 for the PIC16F628 (and many other PICs, but not all). Selection between Bank 0 and Bank 1 is controlled by bit 5 of the STATUS register. When it is clear (equals 0), Bank 0 is selected, when set (equals 1), Bank 1 is selected. Only PORTB concerns us for this short program. Its DDR is known as TRISB. In order to set all eight PORTB pins for use as outputs, as we need to, we first set STATUS to access Bank 1, with the statement: bsf STATUS,5 Command bsf means Bit Set File register – set the named bit (5 in this case) of the named register (STATUS). (The terms ‘set’ and ‘clear’ were defined in Part 1.) The binary value of b’00000000’ (0) is then set into TRISB, with the two commands: movlw b’00000000’ movwf TRISB movlw means ‘move the literal value that follows into the Working Register – known by the letter ‘W’) (‘move’ in this case means ‘copy’ – the original value itself remains where it is, and just a copy of it is placed into the named register). movwf means move (copy) the value in W to the File then named. Thus the value in W is now copied to register TRISB. Any bit set to a 1 in the DDR then behaves as an input pin and any bit set to a 0 can be used as an output (but also see later). The DDR is now configured for all PORTB bits to behave as outputs. All PIC ports can have their DDRs set via a suitable TRIS statement. The PIC16F628 also has a PORTA, which is shown in use next month, and its DDR is set via TRISA. Some PICs have more ports, eg PORTC, PORTD, PORTE and equivalent DDR registers, eg TRISC, TRISD and TRISE. PICs can have any individual bit of any file byte acted upon directly. Each bit can be set high (as above with STATUS – bsf), or low by a single command bcf (Bit Clear File register), which is now used to return the PIC to Bank 0: bcf STATUS,5 As we shall show in a future part, a single command will also determine the status of any individual bit. Now we can change the value within PORTB (and then output byte values to the world) as we wish. Right now we can simply use the command: bsf PORTB,0 This causes the LED on PORTB bit 0 (RB0) to turn on. The next seven lines then cause the other LEDs to turn on in the sequence shown. Two commands remain: nop goto PROGEND Command nop means ‘no operation’, allowing a command to be used but which does nothing except introduce a pause of one PIC clock cycle (whose timed length
27
depends on the rate of the oscillator used). The goto PROGEND command tells the program to go to (loop back in this case) to the Label PROGEND, which immediately precedes nop. The effect is that the program continues doing nothing active – for ever – until it is reset somehow to again perform the same total sequence of commands. Ignore the DELAY calls and routines for the DELAY, DELAY 2. They will be discussed in a later part. Finally, there is the statement END. Not all assemblers/programmers need this statement to indicate that the program has now reached its end. It is best, though, if it is always included.
Listing 2.2 ; TEACHINB03.ASM 07JUN07 - TEACH IN 2008 PT2 ; STATUS Carry flag checking #DEFINE BANK0 BCF STATUS,5 #DEFINE BANK1 BSF STATUS,5 include p16f628.inc CBLOCK h’20’ CLKCNT ENDC
Resetting the program If the PIC were to be installed in another PCB rather than the provided Control one, there might be no way to end this demo program except by switching off its power supply. However, this Control PCB (and the TK3 PCB) has a Reset switch built in, S1. Pressing S1 causes the program to restart from the beginning without power being switched off. There are now two facts that you need to consider, regarding the contents of the resisters, although their effect will not be apparent with this demo. First, using the Reset switch causes all existing register values to remain as they were prior to the switch being pressed. This is beneficial in some applications, such as the single Dice program described later. Perhaps more importantly in other applications, all the values held in the registers are unknown when power is switched on following a switch off. It is usually essential that any register used in the program should always be given a known starting value at the moment of switch on. This will be demonstrated in the Part 3 discussion next month.
STARTIT
28
; internal 4MHz oscillator
ORG 0 goto STARTIT ORG 4 goto STARTIT ORG 5
; reset vector ; Interrupt vector address ; PIC program memory start location
clrf PORTA clrf PORTB BANK1 clrf TRISA clrf TRISB movlw b’10000111’ movwf OPTION_REG BANK0
; clear Port A data register ; clear Port B data register ; BANK 1 ; Port A direction register for output ; Port B direction register for output ; timer 1:256, pull-ups off (bit 7 = 1)
LOOP1
movlw 1 movwf PORTB bcf STATUS,C
; load value of 1 into Working register ; load this value as data into Port B ; clear Carry flag
LOOP2
call DELAY rlf PORTB,F btfss STATUS,C goto LOOP2
goto LOOP1 DELAY
More on LED controlling Let’s examine LED control in a bit more detail, still using the LEDs on the Control PCB. Load program TeachinB03.hex into the PIC and run it. What you will see is that the eight individual LEDs on PORTB are again being turned on at the same time that the preceding one is turned off. The movement will appear to be going from right to left, from bit 0 to bit 7 (D2 to D9), and restarting at bit 0. There are several ways of doing this (and many reasons why you should need to). Two programming techniques are discussed here, the one in Listing 2.2, and then a much shorter one, later in Listing 2.3. The one in Listing 2.2 demonstrates the use of the commands MOVLW, MOVWF, RLF, BTFSS, and how two loops can be ‘nested’ and made dependent upon each other. Referring to the display you see on the LEDs at the moment, controlled by TeachinB03, the Carry bit clearing technique is being used immediately prior to the RLF command. We shall show what happens if the Carry is not cleared when TeachinB02 is viewed later. Listing 2.2 contains the command MOVLW 1. The MOVLW command (MOVe
__config $3F30
movlw 25 movwf CLKCNT clrf INTCON
DELAY2 btfss INTCON,2 goto DELAY2 bcf INTCON,2 decfsz CLKCNT,F goto DELAY2 return
; BANK 0
; rotate value of PORTB left by 1 logical place ; check Carry flag is set ; this command is actioned only if PORTB is ; not yet 0 ; the program jumping back to address ; LOOP2 ; this command is only actioned when ; PORTB now = 0 ; set delay counter to 25 ; (for 1/25th sec x 5) ; clear interupt flag ; ; has a timer time-out been detected? ; no ; yes ; dec counter, is it zero? ; no ; yes
END
Literal value into W, 1 in this case) is the command which allows literal values (numbers) contained within the program itself to be moved (copied) into the Working register for further manipulation. The range of values is from 0 to 255, i.e. an 8-bit byte. Command MOVLW 1 instructs that the value of 1 is to be moved into W. Literal values may be expressed in decimal, hexadecimal or binary, eg: MOVLW 73 (decimal) MOVLW H’49’ (hexadecimal) MOVLW B’01001001’ (binary) Literals may also be the address values of other files whose names have been specified at the head of the program, or they
may be the values assigned to be represented by other words or letters. The following are all legal commands: MOVLW STATUS MOVLW PORTB MOVLW W MOVLW LOOP1 Respectively, the commands would move into W the address value of STATUS (which is specified as 3 for the PIC16F628), the address value of PORTB (6), the value assigned to be represented by W (0), the address within the program at which the command line prefaced by label LOOP1 resides (a value known only to the program unless you examine the LST file).
Everyday Practical Electronics, December 2007
Following the MOVLW 1 command in Listing 2.2 is the command MOVWF PORTB, (MOVe W into File) which simply copies the contents of W into the file specified, in this case PORTB, still leaving that value in W (unimportant in this program, but it can be in other programs). Apart from the destination statement, no commas or other statements are needed (or allowed) with this command. The MOVWF command is the only way in which full bytes of data can be copied from W into other destinations. As used in Listing 2.2, it is the value of 1 which is copied.
Rotation and shifting Many of you will be familiar with the concept of shift registers. Data can be loaded into the register either serially (bit entry) or in parallel (byte entry). The data can be shifted to the ‘left’ or ‘right’ in the chip, in response to a clock signal. The shifted data can then be made available either serially as bits, or in parallel as a byte. When data is shifted left and read as a byte (parallel output), each shift has the effect of multiplying the value by two. Shifting to the right divides it by two. Take the 8-bit binary code 00000100 (decimal 4), for example. If this is shifted left by one place, the result is 00001000 (decimal 8). If the code had been shifted right by one place, the result would be 00000010 (decimal 2). Most files within a PIC are capable of having their data shifted (rotated) to the left or to the right (although doing so on the SFRs may sometimes produce unpredictable results). The two commands are RLF and RRF (Rotate Left File and Rotate Right File). Both commands have to be followed by the file which is to have its data rotated, then a comma and then the destination, either F or W. There are two problems associated with rotating a file’s contents left or right. First, consider the situation when a file (for example, call it PORTB) contains a value such as 11010111 (decimal 215); there are many numbers that could illustrate the point about to be made. Suppose the rotate left command RLF PORTB,F is given, all bits are rotated left by one place. The value retained in PORTB becomes 10101110 (decimal 174) which is definitely not 2 × 215; the original lefthand bit has vanished from this 8bit byte – a 9-bit byte would be needed to show the correct answer. Alternatively, suppose the rotate right command RRF PORTB,F is given, all bits are rotated right by one place. The value retained in PORTB becomes 01101011 (decimal 107), which is definitely not 215/2; the original right-hand bit has vanished from this 8-bit byte. In some cases, of course, the intention of rotating left or right may have nothing to do with multiplying or dividing a value by 2. It may be that we simply want to change the position of the bits for another purpose, such as changing the commands sent to the outside world to turn equipment on or off. In this case, the arithmetic accuracy of the rotate result would be immaterial. The other problem (although it can be used beneficially) is that bits rotated out from either end of the byte are rotated into the Carry bit of STATUS. Simultaneously,
the previous value held in the Carry bit is rotated into the byte at the other end. Suppose that the Carry bit is initially zero. In the first RLF example above, the original value of 11010111 would be rotated left and the result would be correct as shown (10101110) because the 0 has come in to the right from the Carry bit. However, the last lefthand bit of the original value (which is a 1) would now be in the Carry bit. Suppose that another rotate left is made. The bits within PORTB would be rotated left but, at the same time, the Carry bit from the previous rotation would now be rotated into PORTB from the right. The value held in PORTB thus becomes 01011101 (decimal 93), and again the Carry bit now holds the 1 from PORTB bit 7. Therefore, the next rotation will result in an answer of 10111011 (decimal 187). To avoid a set Carry bit (which retains the status last acquired anywhere in the program) being rotated automatically into a file byte from the other end, the Carry bit can be cleared by the command BCF STATUS,C prior to each rotate command, unless, of course you want a Carry bit rotated into a byte.
Bit testing Another command we are introducing in Listing 2.2 is BTFSS, Bit Test File Skip if Set. What BTFSS does is to examine the status of the file bit specified in the remainder of the command (bit C of STATUS in this case: BTFSS STATUS,C). The word Set now becomes the important one. The PIC is being asked to test if the bit specified is Set (ie, is it logic 1?). Programs are stored as instructions in consecutive memory bytes. These bytes are numbered from zero upwards, with location 5 being the true start of the full program for most PICs (although it can be a different later address). In Listing 2.2, we know that the answer from BTFSS will be either true or false. When the PIC performs the BTFSS command, the answer is automatically added to the PCL. Therefore, if the answer is true (1) the PCL has 1 added to it and so the next-butone instruction is performed. If the answer is false (0), then zero is added to PCL and so the very next instruction is performed. With the command BTFSS STATUS,C, we are checking if bit C of STATUS is set (true). If it is true that the bit is set, then the 1 of the truth answer is added to PCL and so the command GOTO LOOP2 is bypassed and that which says GOTO LOOP1 is performed. If STATUS bit C is not set (false) then the program simply takes GOTO LOOP2 as the next command because the 0 of the false answer is added to PCL. What the program of Listing 2.2 does is the simple action of repeatedly ‘moving’ an active LED from right to left. First, at label LOOP1, the value of 1 is moved into W, this is then moved into PORTB, setting its bit 0 to 1 and clearing bits 1 to 7. As a result, the first LED at the right is turned on (D2) and the others (D3 to D9) are turned off. In binary, PORTB’s value is now 00000001. Next, the Carry bit of STATUS is cleared to prevent it from interfering with the results of the rotate-left command that follows at label LOOP2 (as discussed earlier). You will see that this command is RLF PORTB,F. The F suffix means that
Everyday Practical Electronics, December 2007
the result of the rotation is retained in PORTB, and the contents of PORTB will have shifted so that the second LED (D3) has come on because the 1 previously set by the MOVWF command has shifted from PORTB’s bit 0 to its bit 1. Since the Carry bit was previously cleared, 0 is moved into PORTB bit 0, turning off LED D2. The binary value has become 00000010. Now the value of the Carry bit in STATUS is checked to see if a 1 has been shifted out from PORTB bit 7. In fact, it cannot have occurred yet, since it takes eight shifts to bring the 1 from the right and into Carry. However, the PIC is not aware of that fact, so the Carry bit has to be checked following each shift left. If the Carry bit is not yet set, the command GOTO LOOP2 is performed, the program jumps back to that stated position and the RLF command is again actioned. As a result, the third LED (D4) will come on and the second LED (D3) will go out, binary 00000100. Eventually, after eight shifts, the 1 will have shifted through all eight bits of PORTB and into the Carry bit. At this point, there will be no bits set in PORTB, and so no LEDs will be on. Now, on the test for the Carry bit being set, the answer will be true, command GOTO LOOP2 will be bypassed and the command GOTO LOOP1 will be performed, the program jumping to that label. The whole sequence then recommences by a 1 again being loaded into PORTB bit 0. As written, the program will repeat until the PIC is switched off or the Reset switch is used.
Command BTFSC There is a command which is the opposite of BTFSS, namely BTFSC (Bit Test File Skip if Clear). What this command does is to check if it is true that the bit being tested is clear (0). If it is true that the bit is clear, then the answer is 1. If it is false that the bit is clear (that the bit is not 0, but 1), then the answer is 0. Using BTFSC in the program of Listing 2.2 would produce entirely the wrong result. Can you see why?
A faster LED rotation Load the PIC with the program in Listing 2.3, TeachinB02.hex – it will be seen to be shifting the LED display to the left, as occurred when TeachinB03 was run. You should notice that TeachinB02 is running a bit faster than TeachinB03 did. This is because there are now fewer commands to process for the same result. Simplicity of code usually makes for faster processing speeds (or rather, fewer commands to be processed to perform a particular function, will result in a faster processing speed). Look at Listing 2.3 and you will see how few commands there are in the loop, just two. Let’s examine the program flow. In the listing everything up to the statement BANK0 is the same as in TeachinB03. Then advantage is taken of the fact that a set Carry bit will be shifted into a file when it is rotated left or right; the command BSF STATUS,C is given before the loop, so setting the Carry bit. Now when PORTB is rotated left with the command RLF PORTB,F, the Carry bit comes straight into PORTB bit 0, turning on LED D2.
29
Listing 2.3
Parts List – Teach-In 2008 – Part 2
; TEACHINB02.ASM 07JUN07 - TEACH IN 2008 PT2 #DEFINE BANK0 BCF STATUS,5 #DEFINE BANK1 BSF STATUS,5
IC2
PIC16F628, (as listed in Part 1) programmed R1 to R6 470Ω resistors 0.25W (6 off) D1 to D6 red LED (6 off)
include p16f628.inc __config $3F30
; internal 4MHz oscillator
Control PCB (as described in Part 1) Plug-in breadboard, 64 holes long (6.7in x 2.5in), 0.1in pitch Solid, insulated connecting wire
CBLOCK h’20’ CLKCNT ENDC
STARTIT
ORG 0 goto STARTIT ORG 4 goto STARTIT ORG 5
; reset vector
clrf PORTA clrf PORTB BANK1 clrf TRISA clrf TRISB movlw b’10000111’ movwf OPTION_REG BANK0
; clear Port A data register ; clear Port B data register ; BANK 1 ; Port A direction register for output ; Port B direction register for output ; timer 1:256, pull-ups off (bit 7 = 1)
; Interrupt vector address ;PIC program memory start location
; BANK 0 DICELOOP incf PORTB,F incf PORTB,F incf PORTB,F DICEEND nop goto DICEEND
call DELAY
LOOP
DELAY
bsf STATUS,C
; set the Carry bit in STATUS
rlf PORTB,F call DELAY goto LOOP
; rotate left PORTB
movlw 25 movwf CLKCNT clrf INTCON
DELAY2 btfss INTCON,2 goto DELAY2 bcf INTCON,2 decfsz CLKCNT,F goto DELAY2 return
power to the Controller. One or more LEDs will turn on, representing the dice value. Press the Reset switch on the Controller, and the LEDs should show a different value, between 1 and 6. Pressing the switch again will produce a different value, and so on. The rest of the program up to STARTIT, and the next four commands after it, is as you have been using so far. Then follow:
Command INCF
; repeat ; set delay counter to 25 ; (for 1/25th sec x 5) ; clear interupt flag ; ; has a timer time-out been detected? ; no ; yes ; dec counter, is it zero? ; no ; yes
END
Command incf means ‘increment’ (add one to) the value already existing in the named register that follows (PORTB). We don’t actually know what value is aleady in PORTB, as we have not told it to start with any given value (although we can, as we shall see. Should adding 1 to the value within PORTB result in a total of 256, PORTB automatically rolls over to a value of 0. (The range of any 8-bit byte is always 0 to 255.) The same INCF action is performed three times, so each time the switch is pressed, the existing PORTB value simply has three added to it each time the program
Simultaneously, the Carry bit is cleared. The next command is GOTO LOOP, which the program does, again to rotate PORTB, causing D3 to come on and D2 to go out. For eight rotations left, the Carry bit remains clear, then on the ninth rotation the original 1 that has traversed PORTB will drop into the Carry bit, to be rotated back into PORTB on the next rotation. And so it goes on, indefinitely. There are numerous situations in which rotation occurs and when the setting of the Carry bit is desirable. In this way, for example, several files can be coupled as a very long shift register: BSF STATUS,C RLF FILE1,F RLF FILE2,F etc. to RLF FILE15,F
Gaming dice To conclude this month we use LEDs to show the first stages of how a representation of the dots on a gaming dice can be simulated. The program is shown in Listing 2.4. The circuit diagram we shall use is in Fig.2.1, and the breadboard layout is given in Fig.2.2. Disconnect the LINK A wire on the Control PCB and connect LINK B to ensure that the LEDs are reverse biased. Program the PIC with the hex file required. Connect the PIC Controller board to the breadboard as shown, using insulated solid connecting wires. Switch on the
30
Fig. 2.1. Circuit diagram for the LED control demonstration
Everyday Practical Electronics, December 2007
__config $3F30
; internal 4MHz oscillator
ORG 0 goto STARTIT ORG 4 goto STARTIT ORG 5
; reset vector
There are no definitive answers – this is just to get you thinking as a programmer who has a display idea in mind. You might also care to see what happens if RRF is used instead of RLF in the relevant demos, and what would happen if you incorrectly used W in place of F, or BTFSC in place of BTFSS where appropriate. Common mistakes to make sometimes!
; Interrupt vector address
Next Month
Listing 2.4 ; TEACHINB04.ASM 07JUN07 - TEACH IN 2008 PT2 include p16f628.inc
STARTIT
DICELOOP DICEEND
; PIC program memory start location
bsf STATUS,5 movlw b’00000000’ movwf TRISB bcf STATUS,5 incf PORTB,F incf PORTB,F incf PORTB,F nop goto DICEEND
; all PORTB as output ; data direction register for PORTB ; increment PORTB count ; increment PORTB count ; increment PORTB count
In Part 3 we show how a similar concept can be used to create the example of two normal gaming dice showing the dice dots resulting when they are ‘shaken’ (activated by a switch). The dice dot order will become as normally expected. Several new concepts and commands will be introduced and discussed.
END restarts, thus the number shown on the dice LEDs will be different each time. (Remember what was said about PIC registers and contents at the moments of switch and reset?) (There are, of course, other ways to add to values, as will be discussed in the series.) You will find that the dice display does not following the normal convention. We shall show how this can be changed in Part 3 next month. We shall also take the dice demo a stage further and discuss other commands that can be used with it to extend its usefulness.
Something to think about Until Part 3 next month, have a think about how you would modify the rotating LEDs program so that alternate LEDs are turned on. As to quite how you interpret that is up to you. But imagine the flashing displays around fun fair stalls and think how you might simulate a simple one. Also, try it with every third LED turned off in the rotating display, then every fourth, then every fifth, etc. Keep in mind what was said earlier about chaining registers with some of the rotating values.
Fig.2.2. Breadboard layout for the circuit in Fig.2.1.
ELECTRONICS TEACH-IN BY MIKE TOOLEY plus FREE CD-ROM
OUT NOW
ONLY £6.99 FROM WHSMITH £8.50 including p & p – from our Direct Book Service A broad-based introduction to electronics – find out how circuits work and what goes on inside them. Plus 15 easy-tobuild projects. The 152 page A4 book comes with a free CDROM containing the whole Teach-In 2006 series (originally published in EPE) in PDF form, interactive quizzes to test your knowledge, TINA circuit simulation software (a limited version – plus a specially written TINA Tutorial), together with simulations of the circuits in the Teach-In series, plus Flowcode (a limited version) a high level programming system for PIC microcontrollers based on flowcharts.
Available from larger branches of WHSmith or see our Direct Book Service Everyday Practical Electronics, December 2007
31
Teach-In 2008 Using PIC Microcontrollers Part Three – More PIC Control Concepts Plus Multiplexing JOHN BECKER
L
ast month in Teach In 2008 Part 2, we showed how PIC software could turn on various LEDs in response to commands within program software. The PIC commands involved in the demo program were discussed. We concluded by discussing the first stages of creating a gaming dice simulation, but with their dots not necessarily in the conventional order. This month we show how a similar concept can be used to create the example of two normal gaming dice showing the dice dots resulting when they are ‘shaken’ (activated by a switch). The dice dot order will become as normally expected. Several new concepts and commands are introduced and discussed. The demo program itself is given in Listing 3.1. (Note: line spaces have been omitted to fit listing on one page.)
5
First assemble the breadboard with the components required for the demo circuit shown in Fig.3.1. Connect the board to the PIC as indicated, with the PIC programmed with the hex file for Listing 3.1, Teachincol.hex1. Switch on the power, press the breadboard switch S1, and release it. The LED display will then show some LEDs turned on to represent a double-dice throw. Pressing S1 immediately turns off the the LED display. Releasing it will show a different pair of values. The switch may be pressed as many times as you like, just as you would throw dice in a game. The program first has its function shown as a comment preceded by a semicolon, as was discussed in Part 2. Now, in Listing 3.1, follow the two statements:
#DEFINE BANK0 BCF STATUS,5 ; define STATUS register bit 5 clear, as BANK0 #DEFINE BANK1 BSF STATUS,5 ; define STATUS register bit 5 set, as BANK1 We showed last month that the PIC’s data direction register (DDR) for PORTB can have its bits set for input and output by changing the BANK controlling them through SFR (special function register) TRISB. The STATUS register associated with various functions, such as BANK changing, is frequently needed in PIC software programs. So too are other common PIC commands which may never need changing.
5
Fig.3.1. Circuit diagram for this month’s demonstration is a double dice
24
Everyday Practical Electronics, January 2008
Listing 3.1 ; TEACHINC01.ASM 07JUN07 - TEACH IN 2008 PT3 #DEFINE BANK0 BCF STATUS,5 ; define STATUS register bit 5 clear as BANK0 #DEFINE BANK1 BSF STATUS,5 ; define STATUS register bit 5 set as BANK1
DICE1 DICE2
DICETABLE
STARTIT
DICESTART
DICELOOP
list p=16f628 ; tell MPASM-type programmer to create a list (LST) file __config $3F30 ; internal 4MHz oscillator include p16f628.inc ; bring in all standard register values EQU 'h20' ; user register at 'h20' allocated as DICE1 EQU 'h21' ; user register at 'h21' allocated as DICE2 ORG 0 ; reset vector goto STARTIT ORG 4 ; Interrupt vector address goto STARTIT ORG 5 ; PIC program memory location at which to start goto STARTIT andlw b'00000111 ; restrict val to first 3 bits (max val below 8) addwf PCL,F ; add incoming val in W to program counter (PCL) ; (incoming vals are below 8, so jumps beyond 7 ; not poss.) retlw 'b00000000' ; jump 0 (no dice LEDs to be on) retlw 'b00001000' ; jump 1 (dice LED to be on - bit 3) retlw 'b00100010' ; jump 2 (dice LEDs to be on - bits 1 and 5) retlw 'b00101010' ; jump 3 (dice LEDs to be on - bits 1, 3 and 5) retlw 'b01100011' ; jump 4 (dice LEDs to be on - bits 0, 1, 5 and 6) retlw 'b01101011' ; jump 5 (dice LEDs to be on - bits 0, 1, 3, 5 and 6) retlw 'b01110111' ; jump 6 (dice LEDs to be on - bits 0, 1, 2, 4, 5, 6] retlw 'b00000000' ; jump 7 (no dice LEDs to be on) clrf PORTA ; clear PORTA's output if any clrf PORTB ; clear PORTB's output if any movlw $07 ; needed by some PICs, including PIC16F628 movwf CMCON ; so that PORTA is treated as digital port BANK1 movlw b'00000000' ; all PORTA as output movwf TRISA ; data direction register for PORTA movlw b'10000000' ; PORTB 0-6 as output, PORTB,7 as input movwf TRISB ; data direction register for PORTB movlw B'00000000' ; pull-ups on (bit 7 = 0) (off if bit 7 = 1) movwf OPTION_REG BANK0 btfsc PORTB,7 ; is PORTB,7 low (= 0) (switch pressed) ? goto DICESTART ; no movlw b'00000011' ; yes, turn off DICE1 and DICE2 displays movwf PORTA ; via PORTA clrf DICE1 ; clear DICE1 to zero clrf DICE2 ; clear DICE2 to zero clrf PORTB ; clear PORTB to zero to turn off any LEDs movlw 7 ; add 7 (a prime number) to DICE1 addwf DICE1,F movlw 3 ; add 3 (a prime number) to DICE2 addwf DICE2,F btfss PORTB,7 ; is PORTB,7 hi (= 1) yet (switch released)? goto DICELOOP ; no, continue looping
SHOWDICE movlw B'00000010' ; turn off DICE2, turn on DICE1 movwf PORTA ; via PORTA movf DICE1,W ; get value in DICE1 call DICETABLE ; call value conversion table bsf PORTA,0 ; turn off DICE1 movwf PORTB ; put resulting value in W out to PORTB movlw B'00000001' ; turn on DICE2, turn off DICE1 movwf PORTA ; via PORTA movf DICE2,W ; get value in DICE2 call DICETABLE ; call value conversion table bsf PORTA,1 ; turn off DICE2 movwf PORTB ; put resulting value in W out to PORTB btfsc PORTB,7 ; is switch pressed (PORTB bit 7 clear)? goto SHOWDICE ; no, so repeat multiplexed dice show goto DICESTART ; yes, go back to DICESTART, and do another dice throw END ; end of program code
Everyday Practical Electronics, January 2008
25
Fig.3.2. Breadboard layout for the ‘double-dice’ demonstration circuit in Fig.3.1. As you were told in Part 2, the TRIS registers for most PICs are normally in BANK1, whereas most other SFRs are in BANK0. There is often the need in a program to change between BANKs. It can be useful to be able to use just short commands to cause such actions, without the full command line having to be keyed in. The instruction #DEFINE can be used this way, to define a single word, which the assembly software will replace with the associated correct command line each time it comes across that word in a program. Thus, the action to clear STATUS bit 5 can be told to occur each time the word BANK0 is found. Similarly, with the word BANK1 setting STATUS bit 5. The use of BANK statements is also illustrated a little later in the software. Following the ‘definitions’ is the instruction: list p=16f628 On coming across instructions preceded by ‘list’, assembly programs such as MPASM will produce a List (.LST) file which shows the manner in which the assembly has dealt with the ASM file and its various statements, whether or not they are program commands. Such List files can be useful when developing software and the way in which it has been assembled can be viewed in words. An example of part of a list file for this demo program is shown in Listing 3.2. The comments have been omitted. Different assemblers may have slightly different formats for the way the information is displayed, but the essential information should still be obvious. The List file example shown was created through the TK3 assembly software. Note that this assembler always creates a List file, whether or not a ‘list’ statement has been found. Next, follow the ‘include’ statement explained last month.
26
The next two lines, show how usernamed registers can be specifically allocated instead of using ‘Cblock’. The required name is stated in column one followed in column two by the register value required, e.g. DICE 1 EQU ‘h20’. The ‘Equated’ value here is the earliest available for the PIC16F628. The next six lines are the same as used in Part 2’s software. Ignore label DICETABLE and its entries for the moment – we’ll come back to them shortly. At label STARTIT are now the commands: clrf PORTA clrf PORTB The way in which PIC register files contain initial data at switch on or reset was discussed in Part 2. The PIC’s datasheet shows their status at such times. Now, in this application, we need to ensure that registers PORTB and PORTA have known values in them whenever the program is run. In this case they are told to hold a value of zero, cleared, using the command CLRF (upper or lower case) and the register file that has to be cleared.
Commands CLRF and CLRW Command CLRF stands for CLeaR File and is always followed by a single number or name which indicates the file on which the action is to be performed. The command instructs the PIC that all bits within the stated file are to be cleared. The allied command CLRW (CLeaR Working register) simply clears the contents of the Working register (W) and is used on its own without a subsequent number or name. In practice, this command may be seldom used, the commands MOVLW 0 and RETLW 0 probably finding preference (the latter command is
Parts List Teach-In 2008 – Part 3 IC2
PIC16F628, (as listed in Part 1) programmed R1 to R7 470Ω resistors 0.25W (7 off) D1 to D14 red LED (14 off) S1 Push-to-make switch, PCB mounting Control PCB (as described in Part 1) Plug-in breadboard, 64 holes long (6.7in x 2.5in), 0.1in pitch Solid, insulated connecting wire
discussed in a future part. Command CLRW has, in fact, been dropped from some PIC families. There are no direct opposites of CLRF and CLRW, which will set all bits high; other techniques have to be used for this action.
Register CMCON Many PICs can have their ports used in various ways, as digital inputs and outputs (I/O) for example. Some can also be used for analogue purposes, such as comparison of analogue voltage values or analogue-todigital conversion (ADC). The PIC16F628 can provide comparison of input pin voltage levels in relation to other values set within the software. That is the mode to which PORTA is automatically set at switch-on. To use PORTA for digital I/O, it needs to be specifically set for that mode, using the two commands: movlw 7 movwf CMCON
Everyday Practical Electronics, January 2008
Listing 3.2 C:\PIC\TEACHIN2008\TEACHINC01.ASM LIST FILE 10-25-2007 19:27:50 This file is for information only and is not for editing A ++ symbol beside column 1 indicates an Include program file (but not headers) A +M symbol beside column 1 indicates a MACRO A ## symbol following binary value indicates a source code error in that line. Some error types not indicated here, but are given in the errors file. NOTE THAT LIST COUNT OMITS STATEMENTS FROM ‘INCLUDE’ FILES THAT HOLD REGISTER EQUATES (e.g. P16F628.INC) List count deci
Prog Prog Code Code count count value value deci hex hex binary
Input file line count deci
Source code
0001 0002 0003 0004 0005 0006 0172 0173 0174 0175 0176 0177 0178 0179 0180 0181 0182 0183 0184 0185 0186 0187 0188
0 0 0 0 0 0 0 0 0 0 0 0 4 0 5 0 0 6 7 0 0 8 9
1 2 3 4 5 6
#DEFINE BANK0 BCF STATUS,5 #DEFINE BANK1 BSF STATUS,5 LIST P=16F628
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0004 0000 0005 0000 0000 0006 0007 0000 0000 0008 0009
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 2810 0000 2810 0000 2810 0000 0000 3907 0782 0000 0000 3400 3408
00101000 00010000 00101000 00010000 00101000 00010000 00111001 00000111 00000111 10000010 00110100 00000000 00110100 00001000
There is no need to concern yourself at this time with why the value of 7 needs to be placed into register CMCON, just remember that these two commands are needed for PIC16F628s (and some other PIC devices, including the PIC16F627) in order to use PORTA in digital mode. But also be aware that other PIC families may have different requirements, or none at all. Then follows an example of how BANK statements are used in place of keying in the commands for setting and clearing STATUS bit 5: BANK1 movlw b’00000000’
; all PORTA as output movwf TRISA ; data direction register for PORTA movlw b’10000000’ ; PORTB 0-6 as output, PORTB,7 as input movwf TRISB ; data direction register for PORTB movlw B’00000000’ ; pull-ups on (bit 7 = 0) (off if bit 7 = 1) movwf OPTION_REG BANK0 PORTA needs to be initialised for all its pins to be used as outputs (although in this program only bits 0 and 1 are actually used) and so is cleared to zero. With PORTB, bits 0 to 6 (right to left) are to be
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
used as outputs, but bit 7 will be used as an input to monitor the status of the ‘dice shake’ switch, and so is set to 1. While still in BANK1 mode, the behaviour of PORTB’s pins that are in input mode can be set so that ‘light pull-ups’ are applied to them (avoiding the need for external biasing via resistors. Bit 7 (far left) of OPTION_REG is the bit that controls these pull-ups. A value of 0 turns them on, a value of 1 turns them off.
Main start At label DICESTART begins the real program, everything until now has been preparatory. First, PORTB bit 7 is read to see if it is low – btfsc PORTB,7 – which it will not be if the switch is not pressed, as the light pull-ups have been turned on earlier. Since the answer is untrue (false), an immediate jump back to DICESTART is made. This check is then repeated, ad infinitum, until the switch is pressed, when the check will cause the next command to be actioned instead of the jump back. This next command is movlw b’00000011’, and the specified value is then placed into PORTA. The reason for this is connected with multiplexing the two blocks of LEDs, and will be explained presently. DICE1, DICE2 and PORTB are then cleared. At label DICELOOP, a value of 7 is loaded into W and added to the
Everyday Practical Electronics, January 2008
__CONFIG $3F30 INCLUDE P16F628.INC ; endinclude P16F628.INC DICE1 EQU H’20’ DICE2 EQU H’21’ ORG 0 goto STARTIT ORG 4 goto STARTIT ORG 5 goto STARTIT DICETABLE: andlw b’00000111’ addwf PCL,F retlw b’00000000’ retlw b’00001000’
contents of DICE1. The subject of adding values will be dealt with more thoroughly later in the series. DICE2 also has a value of 3 added to it. Both values are prime numbers to ensure that a fair degree of randomness appears to hold true with regard to the resulting dice throws when the switch is released. The DICE registers are 8-bit registers and when a value is added to the existing value and the result is greater than 255, a ‘roll-over’ back to 0 is made, plus the difference between the total value and 255. Following the addition, a check of the status of the switch is made, and if it is still pressed, the additive loop is repeated. If the switch has been released, the routine starting at SHOWDICE is entered. Ignoring the command to write data to PORTA for now, the value held in DICE1 is copied into W, and the command call DICETABLE is then actioned, the programming jumping to the earlier, undiscussed, routine commencing at DICETABLE.
Tables PICs, and other microcontrollers, have the ability to jump to given statements within a table, depending on the value held in W when the table is entered. In Part 2, the Program Counter was mentioned in passing in relation to bit testing. It is the Program Counter’s Low (PCL) aspect
27
which is now brought into play. (There is a Program Counter High – PCH – but its use is more complex and is not discussed now). The Program Counter keeps track of which commands are being actioned in various ways, and which command is the next to be actioned. Its existing value can have another value added to it and the command then actioned is the one pointed to following the addition. With a table, the value in W is added to PCL and the table command pointed to by the new value is actioned. Taking the first five lines in DICETABLE: andlw b’00000111’ addwf PCL,F retlw ‘b00000000’ ; jump 0 retlw ‘b00001000’ ; jump 1 retlw ‘b00100010’ ; jump 2 The first command ANDs the value with binary 00000111 (decimal 7) to restrict it to just eight values max (0 to 7). The next command is addwf PCL,F – add the value in W to the value already in PCL (the program counter value). The value of W has already been placed into it prior to the call to the table. In the case of the W value being 0, the Program Counter’s new value is the same as it would be had 0 not been added to it. Then the next command (at jump 0 – retlw ‘b00000000’ is performed. Command retlw, means ‘return to where the call to the routine was made from, with the specified value held in W’. In this instance, the call was made from the command call DICETABLE, and the specified value is (in binary in this case) ‘b00000000’. The program thus returns to the command immediately following call DICETABLE, which is bsf PORTA, 0 to turn off DICE1 then the value of 0 is output to PORTB, which means that no LEDs will be turned on. Had W held a value of 1 in it, then jump1 would have been actioned, with ‘b00001000’ now held in W. Outputting this value to PORTB would result in PORTB bit 3 being set high, and applied to both LEDs attached to that port pin. With W originally holding a value of 2, there would be a return with W now holding ‘b00100010’, and that would be output to PORTB, turning on its bits 1 and 5. The reason for the andlw b’00000111’ command at the start of DICETABLE, is to restrict the possible number of jumps that could be called to a maximum of eight (0 to 7). Without this limit, the program could become confused if the value is greater than the number of jumps available! There are several ways in which the value can be limited, apart from ANDing. Some of them will become apparent as we progress through the series. The DICETABLE is called twice, once for each of the DICE counters. Each time the resulting value is output to PORTB. The reason for not seeing two images simultaneously is the next topic, but first, the conclusion of the main loop: Following the second output to PORTB, switch S1 is again checked. If S1 remains unpressed, the SHOWDICE routing is repeated. If it is now pressed again, a jump is made to DICESTART, and a new dice value is established and shown.
28
Multiplexing
ANDLW B’01011001’
In the SHOWDICE routine, both DICE values are output to PORTB. The use of multiplexing allows the two values to be shown on different groups of LEDs. The technique simply involves only turning on a particular LED group immediately prior to, or after, a value has been sent to it. In theory, there will be is a very brief period when the LEDs still have the wrong value output to them, but the changeover is too fast for the human eye to see. Multiplexing is achieved here by using PORTA to switch repeatedly between the displays of DICE1 (LEDs D1 to D7) and DICE2 (LEDs D8 to D14). The cathodes (k) of each LED group are commoned, and the connection between a cathode group and the 0V line is only established alternately. Using the LINK A wire on the Control PCB LEDs last month, was a fixed example of this. PORTA bits 0 and 1 cause the switching, and their setting and clearing depends on which group is needed to be displayed. Take DICE1 for example. Its cathode group is connected to PORTA,0. Whatever value is applied to PORTB, those LEDs will only be turned on if the 0V connection for them is made by PORTA,0 being low. When that pin is high, that group is turned off. Similarly, for the DICE2 group – their cathodes are commoned to PORTA,1. To turn on the displays for the DICE1 LEDs, the display value is written to PORTB, and PORTA has a value of b’00000010’ written to it. This turns off the DICE2 LEDs, and turns on the DICE1 LEDs. Conversely, for DICE2, its value is written to PORTB, and PORTA has b’00000001’ written to it, thus turning off the DICE1 display and turning on DICE2. Multiplexing is a very powerful tool, as is the use of Tables.
ANDing Now let’s look at two of the commands introduced here, ANDLW and ADDWF. Commands ANDWF and ADDLW will also be examined shortly. As no doubt most of you are aware, if one binary number is ANDed with another, then only if the same bits of both numbers are set (1) will the answer also have a 1 in that position. Any zeros on either or both sides for any bit will automatically produce a result of 0, eg: First number : Second number :
01110010 01011001
ANDed answer :
01010000
This technique is widely used in electronics and computing, the final answer determining the subsequent action to be taken by a circuit or software routine. There are two ANDing commands available with PICs, ANDLW (AND Literal with W), and ANDWF (AND W with File value). Suppose that the first number in the foregoing examples (01110010) is already contained within W, we then wish to AND it with a fixed number as stated in a program command. Assuming that the fixed number is the second number quoted, the command is:
The PIC ANDs the second (literal) number with that already held in W. The answer (01010000) is retained by W and is available to be further manipulated or copied into any file as specified by the command which follows ANDLW. You could, for example, use the command MOVWF PORTB which will turn on any LEDs associated with that value. Any of the three numerical formats may be used with ANDLW, eg B’00011111’ (binary), H’1F’ (hexadecimal), 31 (decimal), are all legitimate and equal. The command ANDWF is used to AND an existing value within W to a value within a named file, either retaining the answer in W (ANDWF FILENAME,W) or putting it back into the named file (ANDWF FILENAME,F). It is not possible to directly AND the contents of two files together, the value of one or other file must have already been moved into W before the ANDing can take place. With both commands ANDLW and ANDWF, if the answer is zero, the Zero flag of STATUS is set. If the answer is not zero, the Zero flag is cleared. Zero is the only flag affected by an AND command.
ADDing There are two ADDing commands available with PICs, ADDLW (ADD Literal to W), and ADDWF (ADD W to a File value). Command ADDLW is used where a fixed number (literal) within a program is to be added to an existing value within W and which has been obtained by a previous operation. Suppose that W holds the answer produced in the previous ANDing example, 01010000 (decimal 80), and you wish to add a fixed value to it, 53 decimal (00110101), for instance. The command would be: ADDLW 53 (or ADDLW H’35’ hexadecimal), (or ADDLW B’00110101’ binary). The answer in this instance is 10000101 (decimal 133) and is retained in W for further use or copying into a file, e.g. MOVWF PORTB. Command ADDWF adds the contents of W to the value within a stated file. The answer can be held in W (ADDWF PORTB,W) or put back into the named file (ADDWF PORTB,F). Three flags within STATUS are affected by any ADD command, Carry, Zero and Digit Carry. If the answer to an addition is greater than 255, the Carry flag is set, otherwise it is cleared. If the answer equals zero, the Zero flag is set, otherwise it is cleared. The third flag, Digit Carry (bit DC of STATUS), you have not encountered yet. Although the concept is not illustrated until later, it is appropriate to describe it now. If you imagine that an 8-bit binary number (eg 10110110) is split into two halves (known as ‘nibbles’), 1011 and 0110, the righthand nibble is monitored by the PIC as a separate item and it is served by its own flag, the Digit Carry flag. If an addition takes place which produces a result greater than 15 (binary 1111) for that nibble, the Digit Carry flag is set, otherwise it is cleared.
Everyday Practical Electronics, January 2008
Command MOVF Whereas MOVLW means moving a literal value into W, MOVF means MOVe File value. The file (assuming PORTB in this case) is named following the command, but the command itself does not say where the value is to be moved to (unlike MOVLW, where W as the destination is included in the command). The destination is stated by adding a comma after the file name and then adding either W or F, eg: MOVF PORTB,W or MOVF PORTB,F Normally, the command would be used with W, so that the contents of the file are brought into W for presumed further use. At first, then, the concept of using F as the destination seems strange. Why move the file value back into the file without the value having undergone some sort of manipulation? The reason is that many commands automatically affect various flags in the STATUS register, setting or clearing them as appropriate. We have already shown how some STATUS flags are affected by some actions. When command MOVF is performed, irrespective of the W or F destination, the Z flag is affected. It is set if the file value is zero, cleared if the file value is greater than zero. So if we wish to know whether or not the file value is zero, we can use the MOVF command to affect the zero flag, and do so without changing the file value. It is is also significant that the existing contents of the W register are not affected when using the F destination, and can therefore be used elsewhere if needed following the result of the zero check.
Command CALL Programs can be written as a series of sub-routines which can be reached in one of three ways, directly by default (without being told to go there), via a GOTO command, or by a CALL command. (Routing following automatic detection of an interrupt event is another matter and is discussed later in the series.) We have shown several examples of the first two. However, a CALL command can be used if one routine needs to make use of another and then, once that has been completed, for the program to jump back to
continue from the command that follows the call. The use of sub-routines allows the same routine to be accessed from many other areas within the overall program, so saving on program space. A second command always has to be used before the program returns to the calling origin. That command takes one of two forms, RETURN (which is an obvious command – return to where you came from) or RETLW (RETurn to where you came from with a Literal value held in W). There is a third return command, RETFIE, which we shall meet later in connection with interrupts. A GOTO command can never be used to end a sub-routine call – the PIC will continue to expect a return command and, if repeated calls to a sub-routine are made without a RETURN or RETLW command, it will become confused and unpredictable results could occur. For example, the following is ‘illegal’: PROG1 PROG2
CALL PROG2 GOTO PROG1 GOTO PROG1
This is ‘legal’, though: PROG1 PROG2
CALL PROG2 GOTO PROG1 RETURN
When the program returns from a CALL following a RETURN command, the contents of W are those which were put there by the last command which used W. Consequently, you can perform a complex sub-routine, end up with an answer in W and, using the RETURN command, return to the main program with that result still retained in W. Command RETLW, though, returns to the main program with W holding the value which RETLW has acquired as part of that command. A literal value is always specified as part of the RETLW command, eg RETLW 127 or RETLW 0. That value replaces any other value within W and is the one which is held in W on the return to the calling point. The value may be expressed in decimal, hexadecimal, binary or as a ‘named’ value defined during program initialisation.
Stack function It is important to be aware that PICs have a limit to the number of calls that can be nested (calls being made from within calls). This is due to the PIC’s Stack (the area that monitors the return addresses when calls are completed) being limited to only eight address values. If the Stack receives more than eight addresses it will over-write the earlier ones, causing a program crash. There is no way to directly read or write to the stack or to determine how full it is (other than through a program simulator). It is, therefore, imperative that if you are using nested calls then you must keep very careful track of how many you are using. In such cases consider whether you could achieve the same result by using GOTO commands for some of the calls, or by returning to the previous calling routine before making the next call.
Another thing to think about To keep your mind active until Part 4, imagine you are writing a program to control a lift. Just using LEDs to indicate what action is on or off, set up a few switches, like door open or close, motor on or off, floor level reached etc, and allow suitable pauses between an action starting and finishing. Add whatever features you want in the interests of safety. Having written the program as though the controls are outside the lift, rewrite it from the point of view of an operator inside. You are welcome to add additional LEDs if you wish, and to use binary values rather than decimal in terms of floor display. Again, there are no definitive questions or answers – it’s just to put your imagination to work again.
Software The software for Teach In 2008 Parts 1 to 3 is available for free download via the EPE website at www.epemag.co.uk.
Next month In Part 4 next month, we show how to use alphanumeric liquid crystal displays (LCDs) and illustrate their use through a breadboarded Event Counter.
ELECTRONICS TEACH-IN BY MIKE TOOLEY plus FREE CD-ROM
OUT NOW
ONLY £6.99 FROM WHSMITH £8.50 including p & p – from our Direct Book Service A broad-based introduction to electronics – find out how circuits work and what goes on inside them. Plus 15 easy-to-build projects. The 152 page A4 book comes with a free CD-ROM containing the whole Teach-In 2006 series (originally published in EPE) in PDF form, interactive quizzes to test your knowledge, TINA circuit simulation software (a limited version – plus a specially written TINA Tutorial), together with simulations of the circuits in the TeachIn series, plus Flowcode (a limited version) a high level programming system for PIC microcontrollers based on flowcharts.
Available from larger branches of WHSmith or see our Direct Book Service Everyday Practical Electronics, January 2008
29
Teach-In 2008 Part Four – Using alphanumeric LCDs under PIC control
JOHN BECKER
I
n this fourth part of Teach In 2008, we show you how to use an alphanumeric liquid crystal display (LCD) with your PIC projects, and then show a demonstration on a breadboard of the LCD being used as the visual output for an event counter. Towards the end of this part we shall say a bit more about the use of switches, particularly with regard to a program’s selective reaction to them. A detailed discussion of the fundamental aspects of an LCD’s control (but not using a PIC) is available for free download from the Resources section of the EPE website at www.epemag.co.uk. The article is called How to use Intelligent LCDs.
LCD connections A standard alphanumeric LCD is used, connected to the Control PCB described in Part 1, and for which pin connections were provided on the PCB – those at the righthand side of the PCB, annotated for LCD use. Referring to Fig.4.1 and ignoring the switches shown for the moment, wire your LCD to a connector suitable for plugging onto the Control PCB LCD pinouts. If you cannot obtain one, then the LCD connections should be hard-wired and soldered to the pins. Ensure you get the connection order correct. Note that there is a variety of LCD pinout formats. Two of the most common are shown in Fig.4.2. Load the PIC with program TEACHIND01.HEX. Once loaded, the program will go straight into the LCD
Fig.4.1. Circuit diagram for the examples in Part 4 demonstration routines and show the simple message READ EPE on line 1 (top line). If it fails to do so, check your connections. Adjust preset VR1 until the best contrast for the display is shown. The source code for the program is shown in Listing 4.1
CBLOCK and ENDC instructions The first five lines of code you have met in previous parts. The sixth line has the indented (column 2) instruction: CBLOCK h'20'
Fig.4.2. Two common arrangements for LCD pinouts
44
You have seen similar in the earlier parts, but the use of CBLOCK has not been explained. CBLOCK is a shorthand instruction which allows a simple technique for specifying user register names and allocating them to PIC addresses without using any address value, except for the value following CBLOCK, h'20'. PICs have one or more areas of memory reserved for user registers. For the PIC16F628, and some other PICs, h'20' (hexadecimal 20) is the earliest address
value which can be used. The area available then extends, for the F628, up to h'7F'. When CBLOCK is specified, any name that follows (set hard left on the screen/file page, in column 1) is allocated an incremental value according to that specified in the CBLOCK statement. Thus, in Listing 4.1, RSLINE is automatically allocated with the address h'20', STORE is allocated as h'21', and so on. The allocation continues until the terminating ENDC statement is found (indented – column 2). Following ENDC, the _config statement is encountered as previously. It is followed by the ORG statements previously discussed.
LCD display program routines We shall not explain in detail how the LCD is actually controlled, simply show how it can be done using a technique which you can follow in your own software. There are two main sections of code that you need for LCD control, both brought in at different program points using include statements. The first is a table
Everyday Practical Electronics, February 2008
used towards the top of the program, in the same place as the table illustrated last month (we shall explain in a future part more about tables and how many you can use). It is in file LCDheader.inc. This file holds the initialisation commands necessary to set the LCD into 4-bit control mode. Whereas include files containing PIC register details, such as p16f628.inc, do not consume PIC memory, other include files containing program commands do consume PIC memory. It is worth remembering this fact if you are working close to a PIC’s memory program limit. Examining a program’s .lst file shows memory use details. Next, follows another table, MESSAG, holding the data for a message to be shown on the LCD’s screen (READ EPE). Neither table is accessed by the program until later. Now follows the instruction to input another include file, LCDroutines.inc. This holds a number of subroutines associated with LCD control, as described shortly. Then comes label STARTIT and the PICs initialisation commands, as discussed previously. The value then sent to the OPTION_REG is different to that previously used. The PORTB pullups are turned off by setting bit 7 to 1, as they are not needed. OPTION_REG’s bits 1 and 2 are also shown to be set. The reason is to do with the PIC’s internal timer, TMR0, being used in this program, and the first three bits (0 to 2) of OPTION_REG determine its rate. This is discussed later, suffice to say for now that use of the timer provides several delay periods necessary for the correct initialisation of the LCD, and is of use for other purposes too, used in earlier parts, but not explained then. The first delay period is called following the BANK0 statement: call PAUSIT. This too will be discussed later. The sub-routine PAUSIT is not shown in Listing 4.1. Now follows call LCDSET. This accesses the routine of that name, held in the LCDroutines.inc file. This routine performs the LCD initialisation. It is followed by another delay caused by the call to PAUSIT. This allows the LCD time to ‘settle in’ to the configuration given to it. A call is then made to the routine starting at label LCDMSG. This sends data for display on the LCD. First, a counter, LOOP, is cleared. Then the command bsf RSLINE,4 is given. This instructs the LCD, via its RS line connected to PORTB pin 4, that the data about to be sent is intended for display, rather than as initialisation commands, for which RSLINE,4 was cleared as part of that routine. The value in LOOP is now copied into W and the table held at MESSAG is called. As discussed last month, the table line pointed to by the value in W is accessed – retlw ‘R’. ‘R’ is the letter required to be shown on the LCD at this moment. The assembly program translates the letter held between the single quotes into its ASCII value. The LCD’s internal character generator then displays the ASCII character specified. The value of LOOP is then incremented, a check is made that the value is not greater than required at this time (btfss LOOP,3),
Listing 4.1 ; TEACHIND01.ASM 25MAY07 - TEACH IN 2008 PT4 #DEFINE BANK0 BCF STATUS,5 #DEFINE BANK1 BSF STATUS,5 list p=16f628 include p16f628.inc
; define register bit 5 clear as ; BANK0 ; define register bit 5 set as BANK1 ; tell MPASM-type programmer to ; create a list (LST) file ; bring in all standard register values
CBLOCK h'20' RSLINE STORE LOOP LOOPA CLKCNT ENDC __config $3F30
; internal 4MHz oscillator
ORG 0 goto STARTIT ORG 4 goto STARTIT ORG 5
; reset vector ; interrupt vector address ; PIC program memory location at ; which to start
goto STARTIT include LCDheader.inc MESSAG addwf PCL,F retlw 'R' retlw 'E' retlw 'A' retlw 'D' retlw ' ' retlw 'E' retlw 'P' retlw 'E' include LCDroutines.inc STARTIT clrf PORTA clrf PORTB movlw $07 movwf CMCON BANK1 movlw b'00000000' movwf TRISA movlw b'00000000' movwf TRISB movlw b'10000110' movwf OPTION_REG BANK0
; (command could be placed later) ; clear PORTA’s output if any ; clear PORTB’s output if any ; needed by some PICs, ; so that PORTA is a digital port ; all PORTA as output ; data direction register for PORTA ; PORTB as output ; data direction register for PORTB ; timer 1:128, pull-ups off (bit 7 = 1)
call PAUSIT MAIN
call LCDSET call PAUSIT call LCDMSG
NOMORE goto NOMORE
; hold here ad infinitum!
LCDMSG clrf LOOP bsf RSLINE,4 LCDMS2 movf LOOP,W call MESSAG call LCDOUT incf LOOP,F btfss LOOP,3 goto LCDMS2 return END
; clear loop ; set RS for data send ; get table address ; get message letter ; show it ; inc loop ; has last LCD letter been sent? ; no, so repeat for next one ; return to the main program
Everyday Practical Electronics, February 2008
45
and if not, repeats the process by jumping back to LCDMS2, displaying the next table letter called. In the counter check, it is known that the table is eight commands long. The binary value for eight is b’00001000’, so it is merely a matter of checking if bit 3 of LOOP is now set, and terminating the loop if it is. There are other techniques available for checking a counter’s status. When loop termination occurs, the program returns to where it came from with the simple command return, to label
Fig.4.3 LCD screen for the first example NOMORE. The action goto NOMORE is now repeated indefinitely until the program is reset or the power is switched off. In another program, any other required routine would normally be entered at this point.
LCDroutines.inc content It is worth highlighting a few other LCD control routines held within the LCDroutines.inc file. The routine we have just used is that at LCDSET. There are also several lines of code which specify the LCD character cell at which a display starts, such as: LCD1: movlw b’10000000’ goto LCDLIN and LCD21: movlw b’11000011’ goto LCDLIN The first specifies that cell 1 of line 1 should be the starting point. The location values are one higher than the binary values would indicate. This is for human convenience only! The initial 1 of the binary value is a code value involved in LCD commands. The next 0 specifies the line (0 + 1 = 1), and the last three digits specify the cell number, in binary (000 in this instance) (0 + 1 = 1). The second example thus specifies that line 1, cell 4 is the starting point (remember, binary value + 1 in each case). The call to LCDLIN causes the command at that point to set the LCD into the mode for dealing with format commands. The command is then sent to the LCD via the LCDOUT routines, which are common to LCD commands and display data. There are also two routines which allow all cells on a given line to be cleared to a blank display – CLRLINE1 and CLRLINE2. Simply calling these routines from a program causes the specified clearance to be done. If there are starting cells other than those already provided for, you may add similar lines for them and resave the file. There is, though, an argument in favour of simply copying/creating cell address lines actually within your program, as they take up program memory, which may be problematic in larger programs running into space shortage.
46
Fig.4.4. Breadboard layout for Fig.4.1 Note that if you do not specify a starting cell address for any new batch of display data, the LCD will simply follow on with the next location which it thinks is available.
Value conversions There is also another include file available, containing other useful LCD routines, LCDconversions.inc: SHOWHEX (show 4-digit hexdecimal value) SHOWDEC (show 5-digit decimal value) BIN2HEX (convert a binary value to hexadecimal) At the head of the file are the register names needed for the routines. Copy them into the CBLOCK section of your program and remove the semicolons from in front of them. The routine at BIN2HEX converts a 2byte binary value (held in CONVCOUNT1 (MSB) and CONVCOUNT0 (LSB)) into a 4-digit hexadecimal value held in CONVDIGIT4 (MSB) to CONVDIGIT1 (LSB). SHOWHEX shows the hex value held in CONVDIGIT4 (MSB) to CONVDIGIT1 (LSB). The routine at SHOWDEC causes the display of a 5-digit decimal value held in CONVDIGIT5 to CONVDIGIT1. To use the routines in this file, copy the values you want into the specified registers (study the .inc file). Then specify the LCD cell at which you wish the display to commence, e.g. call LCD1 to start at line 1 cell 1, and then call the conversion routine, e.g. call BIN2HEX for binary to hexadecimal conversion display.
Event monitor We can now move on to showing how an event monitor can be created, outputting the quantity of events to the LCD for display. The quantity is input in response to pressing two switches, one to count up, the other to count down. Assemble the breadboard as shown in Fig.4.4, with the three switches S1 to S3, the two LEDs D1 and D2, and resistors R1 to R5. The switches are connected to PORTA,
bits 0, 1 and 4, used as inputs. They are biased normally low by the resistors. Pressing a switch applies a high logic level to the associated input. The LED common cathodes are controlled by PORTA bits 2 and 3, with R4 and R5 as their bias resistors. Load the PIC with TEACHIND02.asm and let the program run. Part of its listing is shown in Listing 4.2. Press switch S1 to count up and LED D1 turns on. Release S1 and the LED turns off. Press switch S2 to count down and LED D2 turns on. Release S2 and the LED turns off. While either switch is pressed, a hexadecimal value now appears incrementing (S1) or decementing (S2) on LCD screen line 1, and an equivalent decimal value on line 2. Note that if S2 is pressed and the total count value is already less than certain values, an excessively large number can appear; some of the registers have been at zero, and are now decremented, rolling over from zero to 255. There are ways around this, which should become obvious. Much of the program is the same as in Listing 4.1. The first thing to notice in the full listing (not shown) is the inclusion of extra registers within group 2 in the CBLOCK section. These are to do with the BIN2HEX routine that is called in at the end of the listing via the command include LCDconversions.inc. The third group of registers is for the binary to decimal conversion routine called in at the very end as mathsbin2dec.inc. Next, the previous MESSAG table has been replaced by another called OVERTABLE, with different characters within it.
Switch check Following label STARTIT (Listing 4.2), at MAIN, has been placed a routine to check whether switches S1 or S2 have been pressed. If they have not, the check is again made, repeatedly until one or other is pressed. If S1 has been pressed, the routine at label MAIN1 is entered. The program then turns on LED D1 to indicate that the switch has been pressed (bsf PORTA,2). Register COUNTA is incremented, but with a different command to
Everyday Practical Electronics, February 2008
that previously seen. Instead of incf, the command has become incfsz (increment file, skip if zero). This command increments the register as before, but also performs a check to see if it has rolled over to zero. (Remember that a byte can never hold more than a value of 255, and when that byte is being incremented, it can roll over to zero and then continue counting up again, as previously explained.) If it has not become zero, the next command performed is that at MAIN2A.
Listing 4.2 STARTIT
movwf CMCON
call PAUSIT call LCDSET call PAUSIT MAIN
bcf PORTA,2 bcf PORTA,3 btfsc PORTA,0 goto MAIN1 btfsc PORTA,1 goto DECIT
; no, turn off LED D1 ; no, turn off LED D2 ; is switch S1 pressed? ; yes ; is switch S2 pressed? ; yes
goto MAIN
; no
MAIN1
bsf PORTA,2
; yes, turn on LED D1
MAIN2
; call PAUSIT incfsz COUNTA,F goto MAIN2A incfsz COUNTB,F goto MAIN2A incfsz COUNTC,F goto MAIN2A call OVERFLOW goto WAITRELEASE
; yes, inc COUNTA (LSB), is it = ; zero? ; no, goto MAIN2A ; yes, so inc the next counter byte ; (NSB), is ; it = zero? ; no ; yes, inc the next counter byte ; (MSB), is it = zero? ; no
MAIN2A
call call call call
MAIN3
btfsc PORTA,0 goto MAIN2 call PAUSIT goto MAIN
; is S1 still pressed? ; yes, inc COUNTA again ; allow for switch bounce ; go back and wait next press of S1
OVERFLOW
call LCD1 clrf LOOP bsf RSLINE,4 movf LOOP,W call OVERTABLE call LCDOUT incf LOOP,F btfss LOOP,3 goto OFL2 return
; clear loop ; set RS for data send ; get table address ; get message letter ; show it ; inc loop ; has last LCD letter been sent? ; no, so repeat for next one ; return to the main program
Decrementing The decrementing routines are similar, but do not include an OVERFLOW check for when the count value becomes too low (effectively negative) to be correctly decremented (ways round this will become
; clear PORTA’s output if any ; clear PORTB’s output if any ; needed by some PICs, including PIC16F628 ; so that PORTA is treated as digital port
clrf COUNTA clrf COUNTB clrf COUNTC BANK1 movlw b'00000011' ; PORTA 0 & 1 as input movwf TRISA ; data direction register for PORTA movlw b'00000000' ; PORTB as output movwf TRISB ; data direction register for PORTB movlw b'10000110' ; timer 1:128, pull-ups off (bit 7 = 1) movwf OPTION_REG BANK0
LCD display Now the command call LCD1 is performed, and a routine within the included LCDroutines code sets the LCD to start the display from cell 1 on line 1. The hexadecimal value is then shown via the included file for the LCDroutines code. The LCD starting address is then changed to cell 1, line 2 with the command call LCD21. Following this, a conversion of the binary count to decimal is called within the included mathsbin2dec code. (Some years ago, EPE reader Peter Hemsley wrote a suite of maths programs that were published in EPE. The routines include such functions as binary to decimal conversion, and several others of use to programmers. The full suite is on the EPE Downloads site. The binary to decimal conversion routine has been compiled into the separate mathsbin2dec.inc file used here.) The switch is then checked again to see if it is still pressed. If it is pressed, the counting routine at MAIN2 is repeated. When COUNTA has rolled over to zero, command incfsz COUNTB,F is performed, which does a similar increment and zero check for register COUNTB. If COUNTB has rolled over to zero, COUNTC is incremented. Thus we are building up a 3-byte counter, capable of counting up to 16777215 (256 × 256 × 256 – 1). If any COUNTer has not yet become zero, again the routine at MAIN2A is actioned. When COUNTC becomes zero, the command call OVERFLOW is performed. At OVERFLOW a routine shows the word OVERFLOW, held in the table OVERTABLE. This table is accessed in the same way as the READ EPE message table earlier. Now the WAITRELEASE routine is entered, at which the release of switch S1 is waited, before the process repeats from label MAIN.
clrf PORTA clrf PORTB movlw $07
OFL2
WAITRELEASE
Fig.4.5. LCD screen for the second example
Everyday Practical Electronics, February 2008
LCD1 ; set LCD for display from line 1 cell 1 SHOWHEXVAL LCD21 ; set LCD for display from line 2 cell 1 SHOWDECIMAL
btfsc PORTA,0 ; is S1 still pressed? goto WAITRELEASE ; yes, wait until released call CLRLINE1 call CLRLINE2 goto MAIN ; and start again Continued next page
47
apparent later in the series – we don’t want to overload you with too many commands to take in at one time!)
Listing 4.2 (Continued) PAUSIT
Too fast As will become apparent, the speed of counting can occur faster than you might prefer. The rate can be decreased by inserting a call to PAUSIT at label MAIN2. Delete the semicolon present there to bring that command into play. Once you understand PAUSIT’s timing, you could write a shorter (or longer) delay routine and call that instead. The TMR0 timer and its implications will be discussed in a future part.
PAUSE btfss INTCON,2 goto PAUSE bcf INTCON,2 decfsz CLKCNT,F goto PAUSE return DECIT
Another thing to think about Until Part 5, keep on thinking as a programmer by considering how you would arrange the door switches and displays for use in an aircraft or train WC. You now have an LCD to help with the displays. Keep in mind the privacy of an occupant when present, and let others know whether the WC is free or not. Add whatever features you think might be appropriate, such as extractor fan and motorised WC flush controls. Should you allow its use when standing in a station or on the runway? Questions and answers entirely up to you!
movlw 5 movwf CLKCNT clrf INTCON
bsf PORTA,3 decfsz COUNTA,F goto DEC2 decfsz COUNTB,F goto DEC2 decfsz COUNTC,F
DEC2
; set delay counter to 5 ; (for 1/25th sec x 5) ; clear interupt flag ; initial 1/5th sec wait before setting up LCD ; has a timer time-out been detected? ; no ; yes ; dec counter, is it zero? ; no ; yes ; inc COUNTA, is it = zero? ; no ; dec the next counter byte (MSB), is it = zero ; no ; inc the next counter byte (MSB), is it = zero
goto MAIN2A include LCDroutines.inc include LCDconversions.inc include mathsbin2dec.inc END
www.epemag.co.uk ELECTRONICS TEACH-IN BY MIKE TOOLEY plus FREE CD-ROM
ONLY £6.99 FROM WHSMITH £8.50 including p & p – from our Direct Book Service A broad-based introduction to electronics – find out how circuits work and what goes on inside them. Plus 15 easy-to-build projects. The 152-page A4 book comes with a free CD-ROM containing the whole Teach-In 2006 series (originally published in EPE) in PDF form, interactive quizzes to test your knowledge, TINA circuit simulation software (a limited version – plus a specially written TINA Tutorial), together with simulations of the circuits in the Teach-In series, plus Flowcode (a limited version) a high level programming system for PIC microcontrollers based on flowcharts. Available from larger branches of WHSmith or see our Direct Book Service 48
Everyday Practical Electronics, February 2008
HandsOn Technology http://www.handsontec.com
ISP to ICP Programming Bridge: HT-ICP200 In-Circuit-Programming (ICP) for P89LPC900 Series of 8051 Flash μControllers. ICP uses a serial shift protocol that requires 5 pins to program: PCL, PDA, Reset, VDD and VSS. ICP is different from ISP (In System Programming) because it is done completely by the microcontroller’s hardware and does not require a boot loader. Program whole series of P89LPC900 µController from NXP Semiconductors…
USB-RS232 Interface Card: HT-MP213 A compact solution for missing ports… Thanks to a special integrated circuit from Silicon Laboratories, computer peripherals with an RS232 interface are easily connected to a USB port. This simple solution is ideal if a peripheral does not have a USB port, your notebook PC has no free RS232 port available, or none at all !
Classic P89C51 Development/Programmer Board: HT-MC-02 HT-MC-02 is an ideal platform for small to medium scale embedded systems development and quick 8051 embedded design prototyping. HT-MC-02 can be used as stand-alone 8051μC Flash programmer or as a development, prototyping, industry and educational platform.
For professional, hobbyists…
Teach-In 2008 Part Five – Introduction to timers, BCD counting and equality checking
JOHN BECKER
I
n the first four parts of Teach In 2008, we have covered a fair bit of ground, introducing most of the available PIC commands, and showing how they can be used in a practical situation. Last month, we showed how an Event Counter could be simply implemented. We continue now in Part 5 showing how a similar technique can be used to create a simple frequency counter, basically for use with audio frequencies, in the range of about 20Hz to 20kHz. Although in principle it may seem that a PIC can be used to assess any frequency, in reality it runs at too slow a rate, even with a clock frequency of 20MHz, and its routines have no chance of keeping up with the rate of change of higher frequencies. Certainly a PIC can be used to monitor frequencies significantly above 20kHz, but it needs to be used with normal digital logic chips such as counters, as they have much faster response times.
Clock division A complication arises in that the one second timing routine is governed by a division factor relating to the timer. This factor divides the number of clock cycles generated by the PIC by multiples of two.
Unfortunately, a clock rate of 4MHz, which the PIC has been using, cannot directly provide a timing of exactly one second. If a clock rate of 3.2768MHz is used, then the timer’s division can provide periods of exactly one second. We therefore need to use a crystal of this value to control the PIC’s clock rate. On the Control board, connect a 3.278MHz crystal across the pins provided. The clock frequency generation is now under control of the crystal in conjunction with that board’s capacitors C1 and C2.
Circuit diagram The circuit diagram for the simple frequency counter is shown in Fig.5.1, and its breadboard layout in Fig.5.2. The connections shown at the left-hand side of Fig.5.1 connect to the PIC Master Control PCB. The signal whose frequency is to be counted may come from the output of other digital circuits. It is fed into the DC In point in Fig.5.1. It may swing between 0V and say +5V, although voltage levels somewhat above +5V are prevented from exceeding the PIC’s maximum input voltage level, nominally +5V, by the inclusion of resistor R1 and diode D1.
Fig.5.1. Frequency counter circuit
52
Resistor R1 and diode D2 similarly prevent signals from swinging below about −0.6V and upsetting the PIC. If it is known that signals are swinging symmetrically above and below 0V, then they should be input via AC In and capacitor C1. LCD X1 is the same alphanumeric type whose control was described in Part 4. It is connected to the PIC Control PCB in the same way as before. It shows the frequency value in Hertz (Hz) of the input signal on its top line, and the typical timing of the periodic cycles within the waveform, in microseconds. Load TEACHINE01.HEX and run it. Refer to Listing 5.1.
Counting cycles There are three bytes used as counters in a chain, COUNT0, COUNT1 and COUNT2. Between them they produce a value which can be up to 24 bits long, representing a value of up to 16,777,215 (256 × 256 × 256 −1), the same value as available with last month’s Event Counter, although it can never be reached with this design. Initially, the counter is reset to zero and started. For a period of one second, as set by a timer, the counter counts the number
Fig.5.2. Breadboard layout for Fig.5.1.
Everyday Practical Electronics, March 2008
Listing 5.1 ; TEACHINE01.ASM 09JUN07 – TEACH IN 2008 PT5 __config h’3F21’ MAIN
movlw 25 movwf CLKCNT clrf COUNT0 clrf COUNT1 clrf COUNT2 movf PORTA,W andlw b’00010000’ movwf PREV clrf INTCON
; external xtal oscillator (3.2768MHz)
; get current val of PORTA ; put into prev ; clear TMR0 overflow
MAIN0 btfss INTCON,2 goto MAIN0A bcf INTCON,2 decfsz CLKCNT,F goto MAIN0A goto MAIN3
; has a timer time-out been detected? ; no ; yes ; dec counter, is it zero? ; no
MAIN0A movf PORTA,W andlw b’00010000’ movwf TEMP
; is PORTA = prev?
xorwf PREV,W btfsc STATUS,Z goto MAIN0
; yes
movf TEMP,W movwf PREV incfsz COUNT0,F goto MAIN2 incfsz COUNT1,F goto MAIN2 incfsz COUNT2,F goto MAIN2 call OVERFLOW goto MAIN
; inc COUNTA, is it = zero? ; no, goto MAIN2 ; yes, so inc the next counter byte (NSB), is it = zero? ; no ; yes, so inc the next counter byte (MSB), is it = zero? ; no
; has a timer time-out been detected? ; no ; yes ; dec counter, is it zero? ; no
MAIN3 bcf STATUS,C rrf COUNT2,F rrf COUNT1,F rrf COUNT0,F
; clear carry flag ; divide asnswer by 2
; decimalise answer ; set LCD for display from line 1 cell 1 ; and tell it to expect display data
movlw ‘c’ call LCDOUT movlw ‘y’ call LCDOUT movlw ‘c’ call LCDOUT movlw ‘l’ call LCDOUT movlw ‘e’ call LCDOUT
; GET PERIOD TIMING PERIOD movlw h’40’ movwf REGA0 movlw h’42’ movwf REGA1 movlw h’0F’ movwf REGA2 clrf REGA3 movf STORE0,W movwf REGB0 movf STORE1,W movwf REGB1 movf STORE2,W movwf REGB2 clrf REGB3 call DIVIDE32
call PERIOD call BIN2DEC call LCD21 bsf RSLINE,4 call BLANKIT call SHOWDIGIT8 movlw ‘u’ call LCDOUT movlw ‘s’ call LCDOUT movlw ‘/’ call LCDOUT
Listing 5.1 continued
goto MAIN
MAIN2 btfss INTCON,2 goto MAIN0 bcf INTCON,2 decfsz CLKCNT,F goto MAIN0
call BIN2DEC call LCD1 bsf RSLINE,4 call BLANKIT call SHOWDIGIT8 movlw ‘H’ call LCDOUT movlw ‘z’ call LCDOUT
of changes in logic level of the incoming signal. There are two changes, of course, for each waveform cycle. From logic 0 to logic 1, and then from logic 1 back to logic 0, or vice versa. At the end of each second, the counter is stopped and the value held is divided by two to get the total number of complete waveform cycles occuring during that second. This number, of course, is the value in Hertz. The BIN2DEC routine used last month is then called and the value, which is in binary, is converted to a decimal format and output to the LCD screen, on line 1, followed by the message ‘Hz’. The frequency shown may not be exactly that which would show on a more sophisticated frequency counter, due to the fact that crystal controlled frequency is only correct within a certain tolerance. There is also the fact that the PIC’s software cannot, in this simple program, respond as fast as that which is governed by the response rate of normal digital chips. The value shown, though, is sufficiently accurate for most simple purposes.
; decimalise answer ; set LCD for display from line 2 cell 1 ; and tell it to expect display data
Everyday Practical Electronics, March 2008
movf REGA0,W movwf COUNT0 movf REGA1,W movwf COUNT1 movf REGA2,W movwf COUNT2 return include LCDroutines.inc include MATHSroutines.inc END
53
Cycle conversion Immediately following the display of the frequency, a routine is called in which the frequency detected is converted to an equivalent timing of each complete cycle, in microseconds, using the formula t = 1000000/f, where t = time and f = frequency, and the 1000000 factor is the value needed for converting seconds to microseconds. The frequency-to-cycle timing conversion routine involves a division function to be used. While it is possible to do simple division and multiplication with a PIC, the code required for large numbers is complicated. Consequently, it is preferable to use routines that have been previously written for the job, and are available for public use as library routines. The code was written by Peter Hemsley, referred to last month in connection with the BIN2DEC routine, who provided EPE with suitable division and multiplication routines. These cope with values up to 32 bits long, the length of the values involved in the frequency-to-period conversion now needed. The files are imported at the end of the program code with the command include MATHSroutines.inc. The file says which registers are needed for it to be used, and these have been added to the head of the main program in the CBLOCK section. The MATHSroutines.inc file can be used in your own programs if you wish. The LCD shows the cycle period timing as the value in microseconds, followed by the message ‘us/cycles’.
Timer TMR0 Time now to examine one of the PIC16F628’s timers, TMR0. We’ve been using it to provide the delays needed with the LCD, to provide slowing down delays in some demos, and just now for the frequency timing. It has many uses, providing different timings for different purposes. The PIC16F628 has a special register reserved for use as an 8-bit timer, TMR0 (Timer 0). It divides its input frequency (originating from the PIC’s clock rate timing) by 256 and can be both written to and read from. In most situations though, it is unlikely that you will need to use the read/write facility, but note that if TMR0 is written to, the timer is inhibited from counting for two clock cycles. Probably more useful than writing to TMR0 is to use its output as it occurs naturally at the 1:256 division rate, and then to use the prescaler to subdivide that rate as required. The prescaler divides its input pulses by presettable powers of two. There are eight possible division ratios, which are set in binary form via bits 0, 1 and 2 of the OPTION register. When used with TMR0, the prescaler division ratios are 1:2, 1:4, 1:8, 1:16, 1:32, 1:64, 1:128 and 1:256. The prescaler can alternatively be allocated for use with the Watchdog Timer (WDT – discussed in a future part), in which mode each of these ratios is halved (minimum is thus 1:1 and maximum is 1:128). Note that the OPTION register should not be equated as such, since Microchip previously had a command actually named OPTION and the use of this term
54
in an ASM file assembled by MPASM causes an error condition. Consequently, it is preferable that the register should be equated as OPTION_REG (Microchip’s equated term in their INC files), as we have been using already through Microchip’s named .inc file. You may still sometimes come across the the term OPTION, or even the equated name OPSHUN instead. It should also be remembered that bit 7 of the OPTION register controls the PIC’s light pull-ups facility and should be set high to turn it off, as previously discussed. The PIC effectively runs at one quarter of the stated clock frequency, internal or external. Thus a clock of 4MHz will cause the PIC to run at 1MHz. When TMR0 is used as an internal timer, the pulses it counts also occur at one quarter of the clock frequency. So, if the clock frequency is running at 3.2768MHz, TMR0 will count at 819200Hz and its 1:256 roll-over rate will be 3200Hz. This rate is then divided by the ratio set into the prescaler. If we divide by 32, for example, we obtain the convenient rate of 100Hz. In TMR0 mode, when the prescaler rolls over to zero, a flag is set in the INTCON register, at bit 2. The setting of this
bit can be used as an interrupt, which automatically routes the program to another specified routine, irrespective of which routine is currently being processed, returning to the same point after the interrupt procedure has been finished. The interrupt can also be turned off and INTCON bit 2 read by the program to establish its status, taking action accordingly. Using the timer and the prescaler, you can specify that some actions will only be performed at specified sub-divided values of the clock frequency. Among other things, this allows the PIC to be used as a real-time clock, as well as a frequency counter. Note that the TMR0 rate is set into the OPTION register while in BANK1 mode. This is always the case with this PIC, and many others. First, let’s illustrate the effect of setting different prescaler ratios and, using the LEDs connected to PORTB on the Control PCB, show what happens. Load TEACHINE02.HEX and run it. Refer to Listing 5.2. The program is a modification to that used as the third demo in Part 2, using the PIC’s internal 4MHz oscillator. Disconnect the 3.2768MHz crystal and the LCD. Also
Listing 5.2 ; TEACHINE02.ASM 09JUN07 – TEACH IN 2008 PT2 __config $3F30 STARTIT clrf PORTB BANK1 clrf TRISB movlw b’10000000’ movwf OPTION_REG BANK0 clrf RATE movlw 32 movwf COUNT
LOOP
; internal 4MHz oscillator ; clear Port B data register ; BANK 1 ; Port B direction register for output ; timer 1:2, pull-ups off (bit 7 = 1) ; BANK 0 ; start with a rate of 0 ; starting value for COUNT
bsf STATUS,C
; set the Carry bit in STATUS
call DELAY
; brief pause
rlf PORTB,F call DELAY decfsz COUNT,F goto LOOP movf RATE,W BANK1 iorlw b’10000000’ movwf OPTION_REG BANK0 incf RATE,F bcf RATE,3 movlw 32 movwf COUNT goto LOOP
; rotate left PORTB ; repeat ; timer rate ; BANK 1 ; BANK 0 ; inc rate value ; restrict rate val to 7 max ; reset COUNT val ; repeat
DELAY movlw 50 movwf CLKCNT clrf INTCON
; set delay counter to 50 ; ; clear interupt flag
DELAY2 btfss INTCON,2 goto DELAY2 bcf INTCON,2 decfsz CLKCNT,F goto DELAY2 return
; has a timer time-out been detected? ; no ; yes ; dec counter, is it zero? ; no ; yes
Everyday Practical Electronics, March 2008
reinstate the LED link wire to bring the LEDs back into play. In this program we read the status of INTCON bit 2 rather than using the interrupt facility. The program calls a delay routine at DELAY, clears INTCON,2, then it loops until the bit goes high, to indicate a timer rollover. The essential commands are: clrf INTCON ; clear full intcon register (or just bcf INTCON,2 ; clear intcon register bit 2) DELAY2 btfss INTCON,2 ; is bit 2 high? goto DELAY2 ; no bcf INTCON,2 ; yes, clear bit 2 to allow time to start again (program continues with whatever the user wants) This occurs 50 times a second, as set by this routine into the counter CLKCNT, and then the program continues from where the delay was called, with the command RETURN. Initially, you will see a fairly fast LED movement occurring. It is created with the timer in-circuit with the prescaler set for a minimum division ratio of 1:2. This is because OPTION_REG bits 0 to 2 are set to 000. This rate of counting continues for four cycles of the LEDs rotating through their 8-LED range. The ratio is then set at 1:4 (prescaler value 001), and again another four cycles occur. Similarly, the other ratios are set. The difference in the resulting LED movement rates will become obvious. Having completed the slowest LED movement cycles, the timing speeds up again and the process repeats. The routine can be speeded up, or made slower, by putting a different value into CLKNT (range 0 to 255). Leaving out CLKCNT entirely speeds the routine to the fastest for the timing value held by the timer. Be aware that in the demo the initial flash rates of the LEDs are quite fast.
Binary Coded Decimal counting So far we have illustrated how a count can be increment or added to in binary mode. This resulted in the need for a binary-to-decimal conversion routine in order to show the result on a suitable display, such as an alphanumeric LCD. It is equally possible to count directly in decimal, removing the need for a BCD converter, although the counting rate is slower when using BCD compared to using a binary count. We will now demonstrate the process. We could keep the counted units in one byte, tens in another, hundreds in another, and so on, but, to conserve precious byte space, it is equally possible to use each byte as two 4-bit nibbles, keeping units in bits 0 to 3, and tens in bits 4 to 7. Hundreds and tens of units would be treated similarly in a second byte. For simplicity, now, we concentrate on counting up to 99. First considering the use of two bytes. In 8-bit binary, a value of
decimal 9 is expressed as 00001001, decimal 10 is 00001010, decimal 16 is 00010000. It is obvious that with decimal values we have no single symbol for a number greater than decimal 9. When a value one greater than decimal 9 occurs, we reset the units digit to 0 and add one to the next digit, ie ten is written as 10. While counting in BCD, we can do a similar thing. When the byte holding the units reaches ten, we reset that byte to zero and add one to the next byte. In 8-bit BCD and at a count of nine, the two bytes would read 00000000 (tens) and 00001001 (units). At the count of ten, the bytes become 00000001 (tens) and 00000000 (units). When using two nibbles of an 8-bit byte (instead of the above two bytes), a BCD value of nine reads as 00001001, but a BCD value of ten reads as 00010000. And, for example, a BCD value of 37 reads as 00110111, ie the left-hand nibble (MSN – Most Significant Nibble) holds a value of 3 and the right-hand nibble (LSN – Least Significant Nibble) holds 7. A value of 99 is expressed as 10011001. For a value of 100, both nibbles are reset to zero (00000000) and if there is a byte for hundreds and tens of hundreds, its right-hand nibble (LSN) would be incremented, and so on. Thus, when counting in BCD, we have to check the four bits of the LSN on their own and see if their value is greater than 9. If it is, that nibble is reset and the MSN incremented. The MSN is then taken on its own as a 4-bit value and checked if it is greater than 9. If so, this nibble is reset and the LSN of the next byte incremented accordingly.
Nibble check There are (as in many programming matters) several ways of checking the nibbles for excess values, of which we shall describe one: an additive checking routine. We said earlier that there is a Digit Carry (DC) flag in the STATUS register which signals if the binary value of the LSN has become greater than 15 following an addition. We can use this fact by temporarily adding a number to the LSN which will make the answer greater than 15 if the basic value of the LSN is greater than 9. The number to be added is 6, eg 10 + 6 = 16 with the DC flag set; 9 + 6 = 15 with the DC flag clear. Therefore, to check if an LSN value is greater than 9, we temporarily add 6 to it and check the DC flag. If the flag is clear, the LSN is left as it is. If the flag is set, we increment the MSN and clear the LSN. There is a short cut to doing this, taking advantage of the fact that 10 + 6 = 16, 00010000 in binary. If you look at this answer, the LSN is now zero, while the MSN has been incremented automatically, so representing decimal 10 in BCD. Thus, when we add 6 to the byte as a whole, if the DC flag is clear, no further action on that byte is needed (or on any subsequent bytes for that matter). If, though, the DC flag is set, we simply replace the existing value in the byte with the value now stored temporarily. These commands do the job:
Everyday Practical Electronics, March 2008
INCF COUNT,F ; increment file value MOVLW 6 ; move 6 into W ADDWF COUNT,W ; add it to new file value but keep answer in W BTFSC STATUS,DC ; is the Digit carry flag clear? MOVWF COUNT ; no, it’s set so move W into file, replacing previous value The above check is done in respect of the LSN, but when the DC flag is set, the resulting action changes the value of the MSN, which then has to be checked to see if it (as a 4-bit nibble) is greater than 9, ie is the BCD value of the whole byte now equal to or greater than decimal 100? Again, there is an easy additive technique. If we translate the binary value of BCD 100 (10100000) the decimal answer is 160. If we temporarily add 96 (256 −160) to the whole byte, we can then check the Carry flag (C) to see if it has been set, which it will be if the binary answer has rolled over beyond 255. As before, if the flag is clear, the byte can remain as is; if the flag is set, we replace the value with the temporary one. (Note that the DC and Carry flags are unaffected by an INCF or INCFSZ command.) Here’s the extended routine. Note the inverted logic for checking Digit Carry and Carry flags, BTFSS STATUS,DC in the first instance, BTFSC STATUS,C in the second. INCF COUNT,F MOVLW 6 ADDWF COUNT,W BTFSS STATUS,DC GOTO ENDADD MOVWF COUNT MOVLW 96 ADDWF COUNT,W BTFSC STATUS,C MOVWF COUNT ENDADD (program continues) Let’s look at the BCD additive technique in practice, triggering it from the timer routine: MAIN BTFSS INTCON,2 GOTO MAIN BCF INTCON,2 INCF COUNT,F MOVF COUNT,W ADDLW 6 BTFSS STATUS,DC GOTO OUTPUT MOVWF COUNT ADDLW 96 BTFSC STATUS,C CLRF COUNT OUTPUT MOVF COUNT,W MOVWF PORTB GOTO MAIN In the above listing, note the use of CLRF COUNT before OUTPUT at the end. This can be used here since we know that adding 1 to the count is occurring, rather than adding values of 2 or greater. In the latter instance, the resulting temporary answer must be MOVed into COUNT. Let’s go back to the use of the 3.2768MHz crystal, as we can now move forward to
55
looking at a realtime clock, requiring timed periods of one second, as used with the frequency counting. The config setting is automatically changed by the .hex to suit this external crystal. We can continue with the LED display for the moment. Load TEACHINE03.hex and observe the count incrementing on the LEDs. The prescaler is now run at a fixed ratio of 1:128 and a seconds timing routine is used.
XOR command There is another technique for checking values, using the command XOR. Let’s examine it in principle. The command XOR (Exclusive OR) checks for equality between two numbers. There are two commands, XORLW (XOR Literal with W) and XORWF (XOR W with value in specified File). The latter is followed by the file name, a comma, and the destination (W or F), eg XORWF STORE,W and XORWF STORE,F. You probably know that in electronics there are XOR gates included in the digital logic chip families, and you will no doubt have read descriptions of truth tables relating to just two inputs of an XOR gate (two bits): 0 XOR 0 = 0 0 XOR 1 = 1 1 XOR 0 = 1 1 XOR 1 = 0 As far as a PIC’s XOR function (8 bits) is concerned, the result of XORing two bytes of eight bits is the condition being checked. It is easier here to show the principle by means of switches and an LCD rather than by truth tables. The circuit and breadboard diagrams are shown in Figs 5.3 and 5.4. We use PORTA to monitor the switches, just four of them, S1 to S4, on PORTA bits 0 to 3, along with their biasing resistors, R1 to R4. Biasing is normally low when the switches are unpressed. The appropriate PORTA input goes high when a switch is pressed. Insert the switches and resistors into the breadboard as shown in Fig.5.4. Reinstate the LCD, and disconnect the LED activating link wire. Load the PIC with TEACHINE04.hex, and let it run. Its listing is shown in Listing 5.3. Register TESTVAL is used to hold the basic value against which the value set by the switches is compared. Its value is shown on LCD line 1. The value is set into the program and cannot be changed without reprogramming the PIC. The value set by the switches is held in register VALSTORE and the value is shown on LCD line 2, immediately below the fixed value. The LCD also indicates whether or not the two values are equal, indicated by the STATUS register Z flag. Just a simple technique for showing the binary bit logic is used in the subroutine SHOWBINARY. The message ‘= 0 NO’ is shown to indicate that the truth of the Z flag is false if equality between the two values does not exixt. The message ‘= 1 OK’ is shown to indicate that the truth of the Z flag is true if equality between the two values does exist. In this listing, the value on PORTA is input in the usual way. The next command (ANDLW B’00001111’) is necessary to
56
Fig.5.3. Circuit for XOR Demo this demonstration, since we only want to use the first four bits of PORTA. If PORTA had eight bits that could be used together with associated switches, the AND command would be omitted. The status of each switch is being XORed with the respective bit in TESTVAL, switch 0 with bit 0, switch 1 with bit 1, and so on. If any bit of PORTA is equal to that of the same bit in the XOR command, the same bit in the W register will be cleared. Thus, two zeros will produce a 0, and two 1s will produce a 0. If the bits are dissimilar (1 and 0) the Z bit is set (1). Suppose that the switches produce binary number 0111, the ANDed result in W is 00000111, the sequence of events is: MOVF PORTA,W
check for equality by checking the Zero flag following an XOR command. Nonequality clears the flag, equality sets it. Consequently, following an XOR command you simply check STATUS,Z and route accordingly.
Command OR Although we shall not meet it until later, it is now appropriate to mention that there is an ‘ordinary’ OR command available. It is more correctly termed Inclusive-OR (as opposed to Exclusive-OR). It has two versions, IORLW (Inclusive OR Literal with W) and IORWF (IOR W with value in specified File). The latter is followed by the file name, a comma, and the destination (W or F), eg IORWF STORE,W and IORWF STORE,F.
Seconds counting
answer = xxxx0111 ANDLW 00001111 answer = 00000111 XORLW 00001000 answer = 00001000 Bits that are equal to their counterparts have their corresponding display bits set, those that are not equal have their bits cleared. Take another example:
Moving on from decade counting between 0 and 99, it is an easy step to count in BCD from 0 to 59, accurately simulating the seconds count of a real-time clock. Load TEACHINE05.hex and observe the LCD display. You will see the twin-nibble BCD count on line 2 progressively stepping from zero to BCD 59 (01011001), then
MOVF PORTA,W answer = xxxx0010 ANDLW 00001111 answer = 00000010 XORLW 00000010 answer = 00000000 Here each bit is equal to its counterpart, therefore the answer is zero and, importantly, the Zero flag will have been set accordingly. Therefore, we can
Fig.5.4. Breadboard layout for Fig.5.3
Everyday Practical Electronics, March 2008
Listing 5.3 MAIN
movf PORTA,W andlw b’00001111’ btfsc STATUS,Z goto MAIN movwf VALSTORE movwf TEMP call LCD21 bsf RSLINE,4 call SHOWBINARY movlw ‘ ‘ call LCDOUT movlw ‘=’ call LCDOUT movlw ‘ ‘ call LCDOUT
; set LCD for display data
movf TESTVAL,W xorwf VALSTORE,W btfss STATUS,Z goto M2 movlw ‘1’ call LCDOUT movlw ‘ ‘ call LCDOUT movlw ‘O’ call LCDOUT movlw ‘K’ call LCDOUT goto M3 M2
M3
movlw ‘0’ call LCDOUT movlw ‘ ‘ call LCDOUT movlw ‘N’ call LCDOUT movlw ‘O’ call LCDOUT movf PORTA,W andlw b’00001111’ btfsc STATUS,Z goto M3 goto MAIN
bcf STATUS,C rlf TEMP,F movf STATUS,W andlw 1 xorlw 48 call LCDOUT decfsz LOOP,F goto SB2 return
PAUSIT movlw 5 movwf CLKCNT clrf INTCON PAUSE btfss INTCON,2 goto PAUSE bcf INTCON,2 decfsz CLKCNT,F goto PAUSE return
restart again at zero. On line 1 a seconds count in decimal increments at a rate of one per second, just as an ordinary seconds clock would and, indeed, it should take one minute for the full cycle to occur. In this program, the prescaler rate has been set for 1:128, providing an INTCON,2 pulse rate of 1/25th of second. A counter, CLKCNT, counts down from 25 in response to the pulses. When it reaches zero, it is reset to 25 and a seconds counter, CLKSEC is incremented in BCD. Checking for the BCD count becoming ten is performed by the additive (+6) technique we have already shown. However, checking for the count being at BCD 60 is done using the XOR equality testing method (XOR 01100000 = BCD 60). If equality exists, the CLKSEC counter is reset to zero. In the routine, which shows the decimal count for the seconds, observe how the byte’s MSB (tens) is first extracted using the SWAPF command to temporily swap the two nibbles. ANDLW isolates the new LSN. It is ORed with 48, which converts the value to the ASCII form so that the LCD shows it correctly. CLKSEC is now copied into W, it too is ANDED to extract the LSN units), and ORed with 48 and then output to the LCD.
Another thing to think about
SHOWBINARY movlw 8 movwf LOOP SB2
EXTRA COMPONENTS NEEDED FOR PART 5 3.2768MHz crystal 100n ceramic capacitor, 5.00mm pitch (C1)
; convert to ASCII value
You have a few more concepts to play with now as a programmer. What can you do with the following problem? You have a coin-operated exit control at a car park. Ignoring any offer to accept the fixed payment by plastic card, use switches to represent the value of coins inserted (they are assumed to be legal!). Indicate the coin value accepted and the total value received, opening the barrier when the correct amount has been received. Use a decimal readout on the display. If you think you can provide change, do so! And allow any other features that you might think are necessary. No specific questions or answers – it’s all up to your imagination. You could also think about how you would allow the number of cars coming in and out of a car park to be monitored, preventing its maximum capacity from being exceeded.
PLEASE TAKE NOTE ; set delay counter to 5 ; (for 1/25th sec x 5) ; clear interupt flag ; initial 1/5th sec wait before setting up LCD ; has a timer time-out been detected? ; no ; yes ; dec counter, is it zero? ; no ; yes
Everyday Practical Electronics, March 2008
Teach-In ’08 Part 2 (Dec’04) In Listings 2.1 to 2.3, near the top – CLKCNT should be ranged left (in line with STARTIT), not indented. The CBLOCK and ENDC statements must be indented as shown.
Part 3 (Jan ’08) In Listing 3.1 and TEACHIN C01.ASM amend _config $3F30 to _config h’3F30’ and movlw $07 to movlw h’07’
57
Teach-In 2008 Part Six – 24-Hour clock, frequency generation and data EEPROM
JOHN BECKER
I
n the previous parts of this Teach In 2008 series, we have now told you enough information to create a 24-hour clock. It uses an LCD as the visual output. It is accurate within the tolerence of the crystal. You have been shown how a one second timing routine can be written. That is taken as the starting point now. Next, its rollover rate is fed to a seconds counter, using the BCD counting method. When that reaches decimal 60, it is reset to 0 and a minutes counter is incremented, in BCD. When that reaches decimal 60, it is reset to 0 and an hours counter is incremented, again in BCD. When the hours counter reaches 25, it is reset to 0. In principle a similar process could be used to create a calendar clock, but then the process becomes more complicated as different months have different numbers of days to them, and then there is the question about leap years. It is beyond the role of Teach In 2008 to demonstrate a calendar clock. You have already been shown how to count in BCD. Now we use seperate BCD counters for the seconds, minutes and hours. The program is shown in Listing 6.1. The listing is not explained in detail, but you may use the routines in your own programs as library sections, using the copy and paste method. The circuit diagram and its breadboard layout are shown in Fig.6.1 and Fig.6.2. Assemble the breadboard and connect the LCD. Load the PIC with TEACHINF06.HEX, and run it. To set the clock to the correct time, press switch S2 to increment the hours, at a rate of one per second. Switch S1 increments the minutes. When hours reach their limit of 24, their value rolls over to zero. When minutes reach their maximum of 60, the value also rolls over to zero. Pressing S3 resets the seconds to zero. Adjusting any setting does not affect the other settings. The overall timing accuracy is as good as the frequency tolerance of the crystal allows. Again, there are ways to correct the timing to adjust the accuracy, but such are beyond Teach In 2008.
Fig.6.1 Circuit for the 24-hour clock demonstration
Indirection Register Part of the program in Listing 6.1 uses what is known as Indirect Addressing to
00
Fig.6.2 Breadboard layout for Fig.6.1
Everyday Practical Electronics, April 2008
access registers. This concept also has profound implications for the ability to minimise the number of sub-routines required by a program. Indirect Addressing allows the use of generalised routines which do not apply to any specific register files. The file which the routine accesses is specified prior to entry into the routine and can be changed at will to suit different aspects of the program. The two key commands (or, rather, ‘file registers’) in Indirect Addressing are FSR (File Select Register) and INDF (INDirect File). The idea of Indirect Addressing is that you place the address of the file that you wish to access in register FSR. Commands to access the specified file address are then made via register INDF. Not only does this facility allow the same routine to be applied to different calling routines, it also allows a loop to access a sequence of files without having to specify their individual addresses other than that for one of them in the sequence. In the following example, assume that we have a sequence of files between addresses H’20’ and H’2F’ (16 files), call them FILE0 to FILE15. Their addresses will have been equated at the head of the program in the usual way, usually via the CBLOCK method, although they could be equated seperately. In reality, only the name of the first file is important in this instance. Suppose, for example, we wished to clear all 16 of these files prior to another routine and that we shall do it in ascending order using a loop. Prior to entering the loop we get the address of the first file, in this case FILE0, copy it into FSR and reset the loop counter, let’s call it LOOPA: MOVLW FILE0 MOVWF FSR CLRF LOOPA Now all we need to do is use the following simple routine: RESET CLRF INDF,F INCF FSR,F INCF LOOPA,F BTFSS LOOPA,4 GOTO RESET Command CLRF INDF,F clears the file whose address is held in FSR. Next, INCF FSR,F increments the value held by FSR, in other words FSR is incremented to point to the next file we wish to clear (FILE0 in the first instance of the loop, FILE1 in the next). Next, we increment the loop counter, INCF LOOPA,F, and test its bit 4 (BTFSS LOOPA,4) to see if a count value of 16 (00010000) has been reached (remember we started at 0). If the count is not yet 16, the loop is repeated, GOTO RESET. If the count equals 16, the next command after GOTO RESET is performed, whatever that might be in a full program. Another way of doing it (and there are several ways) is: MOVLW FILE0 MOVWF FSR MOVLW 16 MOVWF LOOPA RESET CLRF INDF,F
Everyday Practical Electronics, April 2008
Listing 6.1A MAIN
btfss INTCON,2 goto MAIN bcf INTCON,2 call CLKADD goto MAIN
CLKADD decfsz CLKCNT,F return
CLKIT
;has a timer time-out been detected? ;no ;yes ;do time ;increment system clock counter. Is it = 0? ;no
movlw 25 movwf CLKCNT call GETKEY incf HLFSEC,F btfsc HLFSEC,0 call CLKIT return
;reset start value of CLKCNT
movlw CLKSEC movwf FSR movlw 3 movwf LOOP clrf STORE1
;get address of CLKSEC ;move it into indirect reg ;set loop to 3
ADDCLK incf INDF,F movlw 6 addwf INDF,W btfsc STATUS,DC movwf INDF ADDCL2 movf STORE1,W call CHKVAL movwf STORE2 movf INDF,W subwf STORE2,F btfsc STATUS,C goto CLKSHW clrf INDF incf STORE1,F incf FSR,F decfsz LOOP,F goto ADDCLK CLKSHW call LCD21 bsf RSLINE,4 movf CLKHRS,W call LCDFRM movlw ':' call LCDOUT movf CLKMIN,W call LCDFRM movlw '.' call LCDOUT movf CLKSEC,W LCDFRM movwf STORE2 swapf STORE2,W andlw 15 iorlw 48 call LCDOUT movf STORE2,W andlw 15 iorlw 48 call LCDOUT return
INCF FSR,F DECFSZ LOOPA,F GOTO RESET You can also use similar constructions to access a sequence of table values (from anywhere within that table) and add them to the values within a sequence of indirectly addressed files, keeping the maximum
;check switch status ;inc half sec counter ;is half second bit clear (= 0)? ;no, it's = 1, so update secs etc ;yes, so don't update secs etc
;inc units - all in BCD ;if 6 is added is there a digit carry? ;yes ;now check if value > allowed value
;is count =< than allowed? ;yes ;no, it's greater, so clear it ;and add 1 to time loop & byte ;dec loop, is it = 0? ;no
;get hrs ;format and send it ;insert colon ;get mins ;decimal point ;get secs ;split & format decimal byte for LCD ;get tens nibble ;ASCII convert it ;send it ;get units ;ASCII convert it ;send it
resulting addition to less than the maximum number of temporary registers that the PIC provides. In the following example, the first address required in the table is at jump 3. This value is first placed into COUNT (MOVLW 3, MOVWF COUNT). We want to start adding the acquired table value to the file starting six bytes beyond
00
Listing 6.1B GETKEY btfss PORTA,1 goto CHKSW2 incf CLKHRS,F movlw 6 addwf CLKHRS,W btfsc STATUS,DC movwf CLKHRS movlw b'00100100' xorwf CLKHRS,W btfsc STATUS,Z clrf CLKHRS goto CLKSHW return CHKSW2 btfss PORTA,2 goto CHKSW3 incf CLKMIN,F movlw 6 addwf CLKMIN,W btfsc STATUS,DC movwf CLKMIN movlw B'01100000' xorwf CLKMIN,W btfsc STATUS,Z clrf CLKMIN goto CLKSHW return CHKSW3 btfss PORTA,3 return clrf CLKSEC bsf HLFSEC,0 movlw 25 movwf CLKCNT goto CLKSHW
FILE0 so the value of 6 is then added to the address of FILE0 and the result placed into FSR (MOVLW 6, ADDLW FILE0, MOVWF FSR). We also want to perform the action five times, so a loop (LOOPA) is set up with the initial value of 5 (MOVLW 5, MOVWF LOOPA). The real action then starts at label GETVAL. The current value held in COUNT is copied into W (MOVF COUNT,W). The table is called (CALL TABLE) and the value held in the table at the location indicated by the value in W is retrieved from the table, being automatically placed into W. The value from the table now in W is then added to the value in the file held via INDF and pointed to by FSR, and the result is stored back into the same file (ADDWF INDF,F). File FSR is now incremented (INCF FSR,F), so incrementing the address of the file held via INDF. Count is incremented (INCF COUNT,F), and LOOPA is decremented. If LOOPA is not yet zero the process repeats. MOVLW 3 MOVWF COUNT MOVLW 6 ADDLW FILE0 MOVWF FSR MOVLW 5 MOVWF LOOPA GETVAL MOVF COUNT,W CALL TABLE ADDWF INDF,F INCF FSR,F
00
;is S1 (hrs+1) pressed? ;no ;check if units >9 ;if 6 is added is there a digit carry?
In another application, the process could have been repeated by constantly incrementing FSR as many times as are necessary. There are many roles in which Indirect Addressing can be used beneficially. You will see other good examples if you examine Peter Hemsley’s BIN2DEC and maths routines.
Commands SUBWF and SUBLW
;yes
;show time setting ;is S2 (min+1) pressed? ;no ;check if units >9 ;if 6 is added is there a digit carry? ;yes ;59 mins max
;show time setting ;is S3 (secs) pressed?
;reset start value of CLKCNT ;show time setting
INCF COUNT,F DECFSZ LOOPA,F GOTO GETVAL In the 24-hour clock program, the three consecutive registers CLKSEC, CLKMIN and CLKHRS are used. It is they which are accessed by the indirect addressing technique when the clock is in normal running mode, in the routine CLKIT. First the address of CLKSEC is moved into W and copied into register FSR. LOOP is then set with a value of 3. At ADDCLK, the file within register INDF, as pointed to by the value within FSR (i.e. CLKSEC) is incremented. Because we are using BCD counters in this program, a value of 6 is then temporarily ADDed to CLKSEC, still via INDF, and the appropriate storing of the value taken if the result has caused the DC flag to be set. Next, the value now effectively in INDF (still CLKSEC) is checked to see if it is greater than that permitted, by comparing it with a preset value held in the table at CHKVAL (not shown) (the use of command subwf is discussed a bit later). Following the check and its resulting action as required, register FSR is incremented (to now point to register CLKMIN). If CLKSEC has now been reset to zero, a similar additive process is repeated for CLKMIN, via INDF, which now points to CLKMIN, whose address is now held in FSR. A similar action for CLKHRS is performed if CLKMIN has become zero, again via FSR and INDF.
In the above discussion, command SUBWF was used, which performs a subtraction process. Let’s examine the two subtraction commands available with PICs. PICs have two subtraction commands, SUBLW (Subtract W from Literal) and SUBWF (Subtract W from File). The latter command is used with either the F or the W suffix, e.g. SUBWF (FILE),F and SUBWF (FILE),W. One might reasonably have expected that SUBLW would actually mean Subtract Literal from W. This is not the case, the subtraction is that of W from the Literal. Consequently, unless you keep your wits about you, this is a command that you could quite easily use incorrectly. In the following code, the value in the file named DEMO is subtracted from 30 and the result put back into DEMO (the first two lines are just to put an initial value into DEMO): MOVLW 20 MOVWF DEMO MOVF DEMO,W SUBLW 30 MOVWF DEMO In this case, the answer is 10 (30 −20), even though instinctively we might have expected 30 to be subtracted from 20. In this next example, to illustrate SUBWF, again it is the value already in W which is subtracted from the value in file DEMO, the result being returned to DEMO. This is more logical. (Once more the first two commands are just to put an initial value into DEMO.) MOVLW 20 MOVWF DEMO MOVLW 5 SUBWF DEMO,F The answer put back into DEMO is, of course, 15 (20 −5). In these two examples, the value subtracted is less than the value from which it is being subtracted. What happens if the opposite is true? For a start, if the value subtracted is greater than the value from which it is being subtracted, the byte simply ‘rolls over’. We have already shown that decrementing a value of zero results in an answer of 255. Decrementing, of course, is simply a subtraction of 1 from a number and we could, therefore, consider the 0 - 1 situation as being expressed (256 + 0) −1 = 255. What we have done by using the addition of 256, is to ‘borrow’ the 256 in order to achieve the correct 8-bit result. The same roll-over situation applies to subtraction of numbers greater than 1. Thus subtracting 20 from 10 produces an answer of 246 (256 + 10 − 20 = 246).
Everyday Practical Electronics, April 2008
We are quite used to ‘borrowing’ in normal arithmetic, so the concept should be familiar to you, although we express the result of subtracting 20 from 10 as equalling −10. The difference with PICs (and other digital devices) is that we cannot produce a negative answer as such. What we can do, however, is to use a flag to indicate that a borrow or negative answer situation has occurred. With the PIC, the Carry bit is used for this purpose. In a subtraction operation we simply test the Carry bit to establish whether or not there has been a borrow. This, though, is where another ‘inverted’ concept has to be applied to SUB commands. Whereas with the ADD commands the Carry bit is Set if a carry result occurs, with the SUB commands the Carry bit is Cleared if a borrow occurs, and it is Set if a borrow does not occur. You could, perhaps, regard the Carry bit as being the bit which is available to be ‘borrowed’ for the subtraction, hence it remaining set if a borrow is not needed, and cleared if it is. The following are examples of routines which test the Carry bit in a subtraction operation: MOVLW 30 MOVWF DEMO MOVF DEMO,W SUBLW 20 MOVWF DEMO BTFSS STATUS,C INCF STORE,F RETURN The above example will cause STORE to be incremented since a borrow will occur when 30 is subtracted from 20. The next example, 30 - 20, does not result in a borrow, so STORE remains at its previous value:
Fig.6.3 Circuit for first sound demo A transistor can act as this interface buffer for a reasonable level of audio output, and a suitable circuit diagram in shown in Fig.6.3, and a breadboard layout in Fig.6.4. Assemble the board and connect it to the Master Control board described in Part 1. It is suggested that you use a pair of personal headphones connected to the output points indicated as LS1. Port A can be used as a counter, incrementing it in a loop as we have shown previously, so automatically toggling RA0 to generate the frequency. Let’s demonstrate this while still using the 3.2768MHz crystal. Refer to Listing 2. Load with PIC with the hex file for the program in TEACHINF01.hex and listen to the headphones. Assuming that the circuit is correctly connected, you won’t hear any sound, it’s toggling far too fast, at around 136500Hz. Even if you were to use PORTB as the counter and RB7 as the output, the frequency would still be a bit too high, at around 136500\128 = 1066Hz. If we use another register as a counter, COUNT0 in TEACHINF02.asm (Listing
MOVLW 20 MOVWF DEMO MOVF DEMO,W SUBLW 30 MOVWF DEMO BTFSS STATUS,C INCF STORE,F RETURN
Fig.6.4 Breadboard layout for Fig.6.3 3) incrementing PORTB as that counter rolls over at 256, we get a frequency range of about 1066\2 = 533Hz from RB0, to around 4Hz from RB7. Between the two methods, we are getting into about the range we need for musical notes. What will be apparent, though, is that if the sound output were coupled to one of the PORTB pins, because the successive outputs each divide the input frequency by two, the resulting ‘notes’ are each an octave lower than the preceding one. What we really need then is a variable additive technique, the additive value more accurately determining the note frequency. For a start, let’s find a value which will
Listing 6.2 ; TEACHINF01.ASM 12JUN07 – TEACH IN 2008 PT6 ; sound generatiom demo 1 #DEFINE BANK0 BCF STATUS,5; define STATUS register bit 5 clear as BANK0 #DEFINE BANK1 BSF STATUS,5 ; define STATUS register bit 5 set as BANK1 list p=16f628
; tell MPASM-type programmer to create a ; list (LST) file
__config $3F21
; external xtal (3.2768MHz)
include p16f628.inc
Sound Generation We now move away from visually demonstrating what’s happening with a PIC program and have look at sound generation. A lot of readers like to use sound in various ways as part of their programs. In essence, the generation of sound is simple, just connect a sound transducer, such as a piezo sounder, between the 0V line and one of the PIC pins, toggle that pin up and down at a suitable rate, and sound is heard. When it comes to tuning that sound to correspomd with a particular musical note, the process starts to become a bit more complicated. To start off with, let’s see what happens when a PIC pin is suitably toggled and it is connect to a small loudspeaker. In themselves, PIC pins cannot provide sufficient current to drive a speaker, a buffer is needed to raise the current available.
Everyday Practical Electronics, April 2008
ORG 0 goto STARTIT ORG 4 goto STARTIT ORG 5 STARTIT movlw 7 movwf CMCON BANK1 movlw b'00000000' movwf TRISA movlw b'00000000' movwf TRISB BANK0 FREQ
incf PORTA,F goto FREQ
; reset vector ; Interrupt vector address ; PIC program memory location at which to start ; needed by some PICs, including PIC16F628 ; so that PORTA is treated as digital port ; all PORTA as output ; data direction register for PORTA ; all PORTB as output ; data direction register for PORTB ; inc PORTA
END
00
Values for the sharps are not given, but their frequencies at RB3 are:
Listing 6.3 STARTIT BSF STATUS,5 movlw b'00000000' movwf TRISB BCF STATUS,5 clrf COUNT0 FREQ incfsz COUNT0,F goto FREQ incf PORTB,F goto FREQ
A# 466Hz C# 554Hz D# 622Hz F# 739Hz G# 830Hz
; all PORTB as output ; data direction register for PORTB
result in a frequency of 440Hz, Concert A in musical terms, putting it out via PORTB,0. Although a formula could be established, it’s actually quite easy to do it with trial and error, trying values and seeing what the result is on a frequency counter. The author has done this countless times in various published projects, operating at different PIC clock rates. We want to allow you to select a few octaves given a basic note value, and we have just said that a binary count produces various octave relationships. If we take the highest value for A that you are likely to find on any musical instrument, we can aim for 440 × 8 = 3250Hz. So first let’s get that frequency appearing at PORTB,0. Refer now to Listing 4 (TEACHINF03.asm). We use two counters, NOTEHIGH1 and NOTELOW1, and the basic values that need to be added to them are held in NOTEMSB1 and NOTELSB1. With a PIC clock rate of 3.2768MHz, the additive factor has previously been found to be decimal 8447, the MSB/LSB values of that are 32 (h’20’) for NOTEMSB1 and 255 (h’FF’) for NOTELSB1 (a total hex value of h’20FF’ = 8447 decimal). Setting that into the program will result in the following frequencies at the PIC pins stated:
It is suggested that you attempt to figure out the MSB and LSB values for the sharps, using the values of the main notes as a starting point. You will spot that A Sharp (A#) is between A and B, and will, therefore, have a value somewhere between the two. Once you start thinking analytically, it should not take long to do, and is a good mental exercise! The two tables in the ASM file can be used to record your results (they are without values for the sharps as shown, but have values for the other notes). The tables, though, are not made use of by this program.
RB0 3250Hz RB1 1760Hz RB2 880Hz RB3 440Hz RB4 220Hz RB5 110Hz RB6 55Hz RB7 22.5Hz
Note RB0 A 3250Hz B 3944Hz C 4184Hz D 4696Hz E 5272Hz F 5592Hz G 6272Hz
RB3 MSB LSB 440Hz 32 255 493Hz 36 248 523Hz 39 57 587Hz 44 5 659Hz 49 108 699Hz 52 108 784Hz 58 204
Decimal 8447 9464 10041 11269 12652 13420 15052
Listing 6.3 movlw 32 movwf NOTEMSB1 movlw 255 movwf NOTELSB1 clrf NOTELOW1 clrf NOTEHIGH1 LOOPIT
movf NOTELSB1,W addwf NOTELOW1,F movf STATUS,W andlw 1 addwf NOTEHIGH1,F movf STATUS,W andlw 1 addwf PORTA,F movf NOTEMSB1,W addwf NOTEHIGH1,F movf STATUS,W andlw 1 addwf PORTA,F goto LOOPIT
00
Music Box
If you have a benchtop frequency counter, monitor each pin of PORTB to prove that the stated frequencies are being output, within a few Hertz, as even crystal controlled oscillators only operate at frequencies within given bands of tolerance (as stated previously and in their datasheets). The respective values for the seven main notes of an octave (excluding sharps and flats) are:
; get fixed val LSB ; add to counter LSB
; carry (if any) add to counter MSB
; get fixed val MSB ; add to counter MSB
Having established the frequencies for musical notes A to G, we now show you how to assemble a simple music box, using switches in place of, say, piano keys for the notes. It outputs notes across one octave. A suitable circuit diagram is shown in Fig.6.5 and its breadboard assembly details are in Fig.6.6. Load the PIC with hex file TEACHINF04.hex and run it. Press any of the keys and the respective note will be heard. Those of you who are musical will know that the first note played usually sets the signature for the remaining notes, but you can only play the respective sharps needed in some cases if you have figured out their frequency generation values. Without those values, pressing a sharp key will produce silence. Also, of course, musically you really need octaves above and below the one used to give a greater range for any tune. That, though is beyond the capabilities of the simple circuit shown, and of the PIC16F628 as more output pins are needed than it has available. This is only a simple music box and it is monophonic, so you can only play one note at a time, and the notes have not been provided with any sort of envelope shaping to provide a decay. Such techniques will not be addressed here. We can next show you how an automatic music box can be created, which plays a sequence of notes when a switch is pressed. Having completed playing the notes, it waits for the next time the switch is pressed, whereupon it plays them again.
PIC Data EEPROM First, though, we introduce another aspect of PICs, the use of their internal EEPROM (electrically erasable programmed read-only memory). This memory can be written to and read from, not quite in the normal way, but the data stored is effectively permanent. The data is not lost when the power is switched off, unlike that for registers in the ‘normal’ memory. There many times that programs can benefit from the ability to store a value or values aquired when running, and for them to be available for access next time the constructed board is switched on and the program re-run.
Everyday Practical Electronics, April 2008
mand prior to the program’s data statements (look at the end of the listing). Again be aware that different PICs can have different data storage areas.
Automatic Music Box
Fig.6.5 Music box circuit diagram Data can be written to the memory in one of three ways:
ɀ via data statements held in a reserved area at the end of the main commands ɀ directly as part of the main program during normal running, storing the results of various operations, for example ɀ by the PIC assembly/programming software through separate routines to those used for normal programming The second technique can be invaluable when debugging a new program you’ve written, allowing the resulting values to be stored to EEPROM for checking later via the assembler’s EEPROM reading facilities (not all assemblers have this facility, although the TK3 program does – read its Notes file for information on how to readback a PIC’s Data EEPROM.
The routines for writing to and reading from the Data EEPROM from within a program will not be discussed, but we show you how to use those routines in situations of your own. It should be noted that different PIC families have slightly different routines, but such routines for some of them are sometimes available for use as library files from several sources, including EPE through past projects. Further data is also on a PIC’s datasheet. Data can be stored using the commands at the end of the program and prefixed by the instruction DE. Any value stored in the EEPROM can be accessed depending on the address value which is called. The range of address values varies between PICs, but for the PIC16F628, there are 128 addresses available, numbered from 0 to 127. The data is actually placed in a consecutive sequence commencing at PIC address h’2100’, which is given as an ORG com-
The circuit diagram for an automatic music box is shown in Fig.6.5. The breadboard layout is shown in Fig.6.6. Load and run program TEACH INF05.hex. Press switch S1 to start the sound playing. There are 13 notes played in sequence. It is a really simple combination of seven notes, starting at A 440Hz and rising to G 784Hz, and then the other way back to A. Sharps are omitted. See the ASM file for the listing. The 12 notes of a complete octave including sharps have been allocated numbers, as was said earlier, from 1 to 12. The order in which those notes are to be played is stored sequentially in the PIC’s Data EEPROM, which is accessed in sequence when switch S1 is pressed. Two tables, NOTEFREQMSB and NOTEFREQLSB, are called to get the relevant note frequency values. The notes are then generated in the same way as before in the previous program. Now, though, they are played for a fixed duration as set by the value set into CLKCNT in the PLAYIT loop. Routine NOTELEN then calls the actual note generation in routine LOOPIT, continuously decrementing CLKCNT at each TMR0 roller until the count has become zero. The value for the next note is then retrieved from the EEPROM and is played in the same way. So the sequence continues until all notes required have been played. This total value is held in the very first available memory location of the EEPROM, and is read at the start of each loop once the switch has been pressed.
Writing to EEPROM If you examine program TEACHINF05.asm, you will see the routine which allows values to be written to the EEPROM (see Listing 6.5) from within the program. The routine is at Label SETPRM,
Fig.6.6 Breadboard component layout for the simple music box circuit of Fig 6.5
Everyday Practical Electronics, April 2008
00
Listing 6.5 ;This routine is entered with W holding ;the eeprom byte address at which data ;is to be stored. The data to be stored ;is held in PROMVAL, which is located in both pages at or above h'70' SETPRM: BANK1 movwf EEADR
bsf EECON1,WREN
;copy W into EEADR to set eeprom address ;get data value from PROMVAL and hold in W ;copy W into eeprom data byte register ;enable write flag
: movlw h'55'
;these lines cause the action required
movwf EECON2
;by the eeprom to store the data in EEDATA ;at the address held by EEADR.
movf PROMVAL,W movwf EEDATA
Fig.6.7 Circuit for 2nd music box which is entered with W holding the EEPROM byte address at which data is to be stored. The data to be stored is held in PROMVAL, which is located in both pages at or above h’70’, as equated. Basically, the routine is one which is provided by Microchip in the PIC’s datasheet and should not be amended, just used as it is. So, when wishing to store the result of an operation in the EEPROM, place the value in PROMVAL, put the address at which you want the value to be stored (between addresses 0 and 127) into W, and simply give the command call SETPRM. The value is then stored as requested. The storage takes a bit longer than if using normal PIC memory, but it is only a matter of milliseconds. Be aware that a PIC’s Data EEPROM has a limited number of times that it can be written to. Although this is many thousands of times, writing to the EEPROM should be used sparing, and never from within a fast loop. PIC datasheets give the operational lifetimes for such actions. But is worth noting that the author has never had a PIC fail because of giving it too many write cycles.
Something Else To Think About Although domesticity may not be your strong point, you want to program the controls for a washing machine. There are many factors to consider, such as cycle timing, door opening and closing, flood avoidance, temperature control etc. Can you come up with something that meets all your imagined needs. You have a lot of programming tools at your disposal now. There’s no reason too why you shouldn’t speed up the 24-hour clock for the sake of simulation, and set up fictitious temperatures, via the EEPROM maybe, or via some other means.
MANUAL
movlw h'AA' movwf EECON2 bsf EECON1,WR BANK0
;set the ``perform write'' flag
CHKWRT: btfss PIR1,EEIF ;wait until bit 4 of PIR1 is set goto CHKWRT bcf PIR1,EEIF ;clear bit 4 of PIR1 return ;******** READ DATA FROM EEPROM ROUTINE ;This routine is entered with W holding ;the eeprom byte address to be read. PRMGET: BANK1 movwf EEADR ;copy W into EEADR to set eeprom address bsf EECON1,RD ;enable read flag movf EEDATA,W ;read eeprom data now in EEDATA into W BANK0 return org H'2100' DE 14 DE 1 DE 3 DE 4 DE 6
; data eeprom address ; 0 number of eeprom addresses needed ; 1 note 1 ; 2 note 2 ; 3 note 3 ; 4 note 4
Correction Teach-In part 2 (Dec ’07) – In Listing 2.1, 2.2 and 2.3, near the top – CLKCNT should be ranged left (in line with STARTIT) and not indented. The CBLOCK and ENDC statements must still be indented as shown.
www.epemag. co.uk 00
Get your magazine ‘instantly’ anywhere in the world – buy and download from the web. TAKE A LOOK, A FREE ISSUE IS AVAILABLE A one year subscription (12 issues) costs just $18.99 (US) Back issues are also available
Everyday Practical Electronics, April 2008
HandsOn Technology Low Cost 8051C Starter Kit/ Development Board HT-MC-02 HT-MC-02 is an ideal platform for small to medium scale embedded systems development and quick 8051 embedded design prototyping. HT-MC-02 can be used as stand-alone 8051C Flash programmer or as a development, prototyping and educational platform
Main Features:
8051 Central Processing Unit. On-chip Flash Program Memory with In-System Programming (ISP) and In Application Programming (IAP) capability. Boot ROM contains low level Flash programming routines for downloading code via the RS232. Flash memory reliably stores program code even after 10,000 erase and program cycles. 10-year minimum data retention. Programmable security for the code in the Flash. The security feature protects against software piracy and prevents the contents of the Flash from being read. 4 level priority interrupt & 7 interrupt sources. 32 general purpose I/O pins connected to 10pins header connectors for easy I/O pins access. Full-duplex enhanced UART – Framing error detection Automatic address recognition. Programmable Counter Array (PCA) & Pulse Width Modulation (PWM). Three 16-bits timer/event counters. AC/DC (9~12V) power supply – easily available from wall socket power adapter. On board stabilized +5Vdc for other external interface circuit power supply. Included 8x LEDs and pushbuttons test board (free with HT-MC-02 while stock last) for fast simple code testing. Industrial popular window Keil C compiler and assembler included (Eval. version). Free Flash Magic Windows software for easy program code down loading. PLEASE READ HT-MC-02 GETTING STARTED MANUAL BEFORE OPERATE THIS BOARD INSTALL ACROBAT READER (AcrobatReader705 Application) TO OPEN AND PRINT ALL DOCUMENTS
http://www.handsontec.com
Teach-In 2008 Part Seven – Using the additional memory banks, plus PCLATH
JOHN BECKER
P
ICs have more data memory available than is apparent at first glance. Under normal programming circumstances, the available memory with a PIC16F628 would seem to be 96 bytes, between h’20’ and h’7F’. In this seventh part of Teach In 2008 we look at ways in which additional PIC memory can be used for data storage and retrieval. We also look at PCLATH, the command that allows tables to be placed anywhere in the PIC’s program memory area. The PIC16F628 has four Banks, two of which were shown in Part 1 Table 1.2. They are all shown in the PIC16F628 data sheet. The first batch of registers in each Bank is associated with the device’s Special Function Registers (SFRs), such as PORTB and TRISB. Some registers are common to each Bank (PCL, STATUS, FSR etc). Others, such as PORTB and TRISB, can be accessed through two Banks each, in this case Bank 0/2 and Bank 1/3 respectively. Below each set of SFRs within the Banks are shown locations that can be used for data storage. With Bank 0, 96 bytes are available for data use, from h’20’ to h’7F’. It is these 96 memory bytes, which will be familiar so far. Normally, 96 bytes is adequate. The availability of additional memory though, can be highly beneficial with more complex programs. Study of the Bank tables shows that Bank 1 has 80 bytes of data memory (general purpose) available, and which are independent of those in Bank 0. Bank 2 has a further 48 bytes that are also independent. However, the upper 16 memory bytes of all four Banks have a common root. Accessing any of these 16 bytes in any Bank automatically accesses those same locations in Bank 0 (h’70’ to h’7F’). Before reading on, assemble the circuit in Fig.7.1, using the breadboard layout in Fig.7.2, and connect it to the Master PCB from Part 1. The switches are not used in the first demo.
Indirect addressing When indirectly accessing the Banks through the use of FSR (File Select Register) and INDF (Indirect File register) 256 addresses can be accessed, either for the combined pair Bank 0 and Bank 1, or
Everyday Practical Electronics, May 2008
Fig. 7.1 Demo circuit for Part 7
Fig. 7.2 Breadboard layout for Fig.7.1 the combined pair Bank 2 and Bank 3. The selection of the Bank pairs is made through the use of STATUS bit 7, known as the IRP bit. Bank 0 and Bank 1 are
selected when bit 7 is low, Bank 2 and Bank 3 when it is high. Because the banks are paired in indirect mode, it is expedient to consider them as two blocks, BLOCKO
49
and BLOCK1, selectable by STATUS bit 7. As such, the command for block selection can also be defined at the head of the program. See Table 7.1, which includes suggested Block definitions.
Example codings
An example of a practical sub-routine for accessing the extra memory is illustrated in part through Listing 7.1 and Listing 7.2. The full source code for the routine is available via the EPE website at www.epemag.wimborne.co.uk in the TeachIn 2008 folder. The file is TeachInG01.asm. For this example, we take the situation where the data source, a counter, is read and the resultant values stored in separate memory locations, using the three available Banks for the storage. There are many ways that the data could be acquired and stored in other situations. The first batch uses the memory area following the main CBLOCK equates, commencing at MEMBANK0 and running through to the end of BANK0 at h’7F’. MEMBANK1 covers the 80 locations from h’A0’ to h’EF’. MEMBANK2 covers the 48 bytes from from h’120’ to h’14F’. MEMBANK3 is not written to, just read, for reasons shown later. Note that Banks 1 to 3 are all equated as h’20’, see the full ASM file. In Listing 7.1 the counter is repeatedly incremented and stored in the memory locations for Banks 0 to 2. At label SAMPLE1 the command for selecting BLOCK0 is first given, and the VALUE counter set to zero. Next, the PIC’s address for MEMBANK0 is recalled through the command movlw MEMBANK0 and the routine at GETBATCH0 is called. The address of MEMBANK0 is now placed into the FSR register, the value in the counter is then moved into W and stored in INDF, which is the location pointed to by the value in FSR. The counter is then incremented, as is the value within FSR. The counter is then checked to see if it is greater than the maximum Bank address available, in this case h’7F’. If it is less than the maximum, a loop back to GETIT0 is made and the process repeats, without the VALUE counter being reset. If FSR is greater than the maximum, a return to the calling point is made. The process continues for BANK1, which covers the bytes between h’A0’ and h’EF’. Note that the bytes betweeen h’F0’ and h’FF’ are not written to – doing so would overwrite the same locations between h’70’ and h’7F’. The process then continues for the 48 bytes available in BANK2. On entry to this routine, the command BLOCK1 is given, to set the correct storage area. At the end of this routine, the block value is reset to BLOCK0. On return, now to the calling point, the command goto PART2 is given and the routines shown in Listing 7.2 are performed. As shown in Listing 7.2, the values stored in the Banks are recalled, converted to decimal and output to the LCD. A short pause occurs between displaying each decimalised value. At SHOWBANK0, first the Bank address is shown on Line 1, the BLOCK
50
Bit 7
Block
0 1
0 1
Banks 0/1 2/3
Table 7.1 Locations Indirect Access Address h’00’ to h’FF’ h’100’ to h’1FF’
#BLOCKO BCF h’03’,7 #DEFINE BLOCK1 BSF h’03’,7
h’00’ to h’FF’ h’00’ to h’FF’ #DEFINE
; clear STATUS bit 7 (IRP) ; set STATUS bit 7 (IRP)
Listing 7.1 SAMPLE1
BLOCK0 clrf VALUE
; set for Block 0
movlw MEMBANK0 call GETBATCH0
; get address of 1st batch in BANK0 ; store values from counter
movlw MEMBANK1 iorlw 128 call GETBATCH1
; get address of 1st byte in BANK1 ; set bit 7 high (b’10000000’ = 128 = ; h’80’) ; store values from counter
movlw MEMBANK2 call GETBATCH2
; get address of 1st batch in BANK2 ; store values from counter
goto PART2 GETBATCH0 GETIT0
GETBATCH1 GETIT1
GETBATCH2 GETIT2
movwf FSR movf VALUE,W movwf INDF incf VALUE,F incf FSR,F movf FSR,W xorlw h’80’ btfss STATUS,Z goto GETIT0 return
; load FSR with value brought in on W ; simulated value to store into memory ; store at address pointed to by FSR ; increment simulation value ; increment address held by FSR ; is FSR greater than max for this Bank?
movwf FSR movf VALUE,W movwf INDF incf VALUE,F incf FSR,F decf FSR,W xorlw h’F0’ btfss STATUS,Z goto GETIT1 return
; load FSR with value brought in on W ; simulated value to store into memory ; store at address pointed to by FSR ; increment simulation value ; increment address held by FSR ; is FSR max for this Bank?
movwf FSR BLOCK1 movf VALUE,W movwf INDF incf VALUE,F incf FSR,F decf FSR,W xorlw h’50’ btfss STATUS,Z goto GETIT2 BLOCK0 return
; load FSR with value brought in on W ; set for BLOCK1 ; simulated value to store into memory ; store at address pointed to by FSR ; increment simulation value ; increment address held by FSR ; is FSR max for this Bank?
value is then set for BLOCK0, the address of MEMBANK0 is placed into FSR and the routine at SHOWVALBANK is called. In SHOWVALBANK, the data within the byte pointed by FSR is recalled, and placed into REGA0 in preparation for the decimalisation process, as discussed in earlier parts of Teach In 2008. Before BIN2DEC is called, the current FSR address is temporarily stored in FSRSTORE, as the decimalisation routine also uses FSR, but for different purposes. Now BIN2DEC is called and the resulting decimal value is now displayed on Line 2.
; no, continue sampling ; yes, end of sub-routine
; no, continue sampling ; yes, end of sub-routine
; no, continue sampling ; return to BLOCK0 ; yes, end of sub-routine Next, the value within FSRSTORE is also decimalised and displayed on Line 2 (not shown in Listing 7.2). There follows a brief pause, allowing the displayed values to be easily seen before the process continues. The pause is caused by the routine at PAUSIT2. Its length maybe changed by altering the value set into CLKCNT. After the pause, the value within FSRSTORE is recalled and placed back into FSR. FSR is then incremented and a return to the calling point is made. The value within FSR is then checked to see if the
Everyday Practical Electronics, May 2008
Listing 7.2
Listing 7.2 (Continued) clrf REGA2 clrf REGA3 movf FSR,W movwf FSRSTORE BLOCK0 call BIN2DEC BSF RSLINE,4 call SHOWDIGIT8
PART2 SHOWBANK0
VAL0
SHOWBANK1
VAL1
SHOWBANK2
VAL2
SHOWBANK3
VAL3
movlw 0’ movwf BANKVAL call SHOWBANKVAL BLOCK0 movlw MEMBANK0 movwf FSR call SHOWVALBANK movf FSR,W xorlw h’80’ btfss STATUS,Z goto VAL0 movlw 1’ movwf BANKVAL call SHOWBANKVAL BLOCK0 movlw MEMBANK1 iorlw 128 movwf FSR call SHOWVALBANK decf FSR,W xorlw h’FF’ btfss STATUS,Z goto VAL1 movlw 2’ movwf BANKVAL call SHOWBANKVAL BLOCK1 movlw MEMBANK2 movwf FSR call SHOWVALBANK BLOCK1 movf FSR,W xorlw h’80’ btfss STATUS,Z goto VAL2 BLOCK0 movlw 3’ movwf BANKVAL call SHOWBANKVAL BLOCK1 movlw MEMBANK3 iorlw 128 movwf FSR call SHOWVALBANK BLOCK1 decf FSR,W xorlw h’FF’ btfss STATUS,Z goto VAL3 BLOCK0 return
; set for Block 0 ; get address 1st byte of 1st batch ; load FSR with value brought in on W
; set for Block 1 ; get address 1st byte of 1st batch ; load FSR with value brought in on W
maximum value has been exceeded. If not, the process repeats for the next stored byte. If so, the next Bank values are recalled and displayed. Note that values from all four Banks are displayed. BANK0 quite correctly displays all the values sent for storage within in it. BANK1 also shows the 80 bytes stored, but then shows the 1 values which are common to all four banks, which in this instance are those sent to BANK0. BANK2 shows the 48 bytes stored, then displays a sequence of zeros for unimplemented locations, followed again by the 1 common values. BANK3 again displays a sequence of zeros for unimplemented locations, followed once more by the 1 common values. Also note that if assembling TEACHING01.asm your programmer may issue warnings that Equates have been duplicated. Ignore the warnings, as the apparent duplication is intended and is in connection with the Bank use.
; set for Block 1
P
; no, continue sampling
; set for Block 0 ; get address 1st byte of 2nd batch ; load FSR with value brought in on W
; no, continue sampling
; no, continue sampling
; set for Block 1 ; get address 1st byte of 1st batch ; load FSR with value brought in on W
; no, continue sampling ; end of sub-routine
call LCD1 BSF RSLINE,4 movlw B’ call LCDOUT movlw A’ call LCDOUT movlw N’ call LCDOUT movlw K’ call LCDOUT movf BANKVAL,W call LCDOUT return
; set LCD for cell 0 line 1
SHOWVALBANK
movf INDF,W
;get value from address pointed to ;by FSR
Everyday Practical Electronics, May 2008
AT
command
Earlier in the series, it was commented in passing that Tables can only be placed within the first 25 bytes of program memory (a page), and anything beyond that would not be accessed correctly, and could cause a program crash. It was said that there were ways round this using the PIC’s PCLATH command, which we now explain. A PIC’s program memory scope varies from 2K to 8K bytes, depending on the PIC type, and is partitioned into 2048 (2K) byte-wide pages. Page boundaries are important when it comes to the use of Tables, and must be complied with for correct operation of the program.
Page allocation
SHOWBANKVAL
movwf REGA0 clrf REGA1
; store FSR
Tables may be put anywhere in program memory space, once the operation of the PCLATH function is understood, and the table is wholly contained within a Page, as it always will be with the PIC1 F 28, which has eight sub-pages, being a 2048 program location device. The program counter (PC) value is held in a 13-bit special function register, which can be regarded as having two parts – PCH (Program Counter High) and PCL (Program Counter Low), for the high and low bytes respectively. PCH resides in the upper five bits of the PC, whereas PCL resides in the lower eight bits. PCL can be written to directly, as is done when normally accessing tables for example, and the response to amending PCL takes immediate effect. PCH, however, can only be written to via the lower five bits of special function register PCLATH. Writing to PCLATH, however, only takes effect when the CALL, GOTO or arithmetic operation involving PCL is performed.
51
It is worth noting that PCLATH is a writeonly buffer. It is not safe to read PCLATH in order to, perhaps, do PC arithmetic.
Listing 7.
etting Program ounter
There are three ways in which the programmer can set a value into the program counter (PC)
clrf PCLATH
; clear PCLATH
LOOP1
btfsc PORTA,0 call TEST1 btfsc PORTA,1 call TEST2 btfsc PORTA,2 call TEST3 btfsc PORTA,3 call TEST4 goto LOOP1
; is S1 pressed? ; yes ; is S2 pressed? ; yes ; is S3 pressed? ; yes ; is S3 pressed? ; yes ; no
TEST1
movlw 1 movwf PCLATH movlw 2 call TABLE1 call PREPBIN2DEC call LCD1 bsf RSLINE,4 call SHOWPAGE
;Set up for sub-page 1
movlw 3 call TABLE1 call PREPBIN2DEC call LCD21 bsf RSLINE,4 call SHOWPAGE clrf PCLATH return
;Get 3rd line from ;1st table
An instruction which carries out an arithmetic operation on the PC. The most commonly used such instruction is adding a value to the PC from the working register (W) when accessing a table, such as A P as you have seen when Tables are used A CALL or GOTO instruction which places the address of a label into the PC A RETURN instruction which places the contents of the stack top into the PC
Arithmetic operations
Arithmetic operations on the PC involve the W register and other 8-bit wide registers. It therefore follows that only PCL can be set with an arithmetic instruction. PCH remains at whatever value it holds at the time of the instruction. It is possible to place a table anywhere in program space by setting PCLATH before the call to the table is made. The purpose of PCLATH is to set PCH for the call itself. The operation code for CALL and GOTO instructions sets 11 bits of the destination address, which is all that is needed in 2K program memory devices. The additional bits are set from PCLATH bit 3 for 4K program memory devices, and bits 3 and 4 for 8K devices.
RET RN instruction
A CALL instruction pushes PCL and PCH values onto the PIC’s stack. A RETURN instruction pops those PCL and PCH values and puts them into the PC, and no manipulation of PCLATH is required. It might be necessary, however, to set PCLATH after the return, as illustrated in the example program partly shown in Listing 7.3 and Listing 7.4. The full program is held in TE I 02 as . The first line in Listing 7.3 sets PCLATH to zero. Then the loop at LOOP1 is entered, in which Port A is constantly read, waiting for one of the four switches, S1 to S4 in Fig.7.2, to be pressed. When S1 is pressed, the routine at TEST1 is called. PCLATH is set with a value of 1 so that TABLE 1, held at the location pointed to by the command org 00 (hex h’12C’), in Listing 7.4 can be correctly called. Note that the 1’ set into PCLATH is the 1’ in the lefthand nibble of the hex value. A value of 2 is now placed into W and TABLE 1 is again called. In the usual way with calling tables, the value held in W is added to PCL, and the corresponding table line is actioned, in this case retlw 12. This places the 12 into W and a return to the calling point is made. Next, a call to PREBINDEC is made. This routine simply places the value of W into REGA1, clears REGA1 to REGA, and calls the BIN2DEC routine so that the value is decimalised. Next, the LCD is set to display the next batch of data, starting at the left of Line 1.
52
TEST2
;Get 2nd line from ;1st table
;Set up for page and sub-page 0.
movlw 2 movwf PCLATH movlw 1 call TABLE3 call PREPBIN2DEC call LCD1 bsf RSLINE,4 call SHOWPAGE
;Set up for sub-page 2
movlw 4 call TABLE3 call PREPBIN2DEC call LCD21 bsf RSLINE,4 call SHOWPAGE clrf PCLATH return
;Get 4th line from ;3rd table
;Get 1st line from ;3rd table
;Set up for page and sub-page 0.
; TESTS 3 AND 4 ARE SIMILAR
Then SHOWPAGE is called, in which the message TABLE’ is output to the LCD, followed by the decimalised value held in DIGIT . The line then displays UMP’, followed by the value held in DIGIT10. In this instance, the value returned from the table call is 12. When decimalised, the lefthand value is 1’, indicating the Table number, and the righthand value is 2’, representing the ump value. All the tables have values which are interpretted in this way. In TEST1, TABLE1 is again called to access the third line. The resulting value is then displayed on Line 2, similarly to Line 1. At the end of the routine, PCLATH is cleared and a return to the switch testing LOOP1 is made. Other switch presses call the corresponding routines, all of which are arranged in a similar manner to TEST1, calling the tables at varying locations within the PIC’s memory.
Programmer s task
Every CALL and GOTO, and every arithmetic operation affecting the PC, requires that PCLATH contains the correct value for the operation concerned. Sometimes, for example, GOTO is used in a timing loop, which might have to allow for two additional PCLATH-setting instructions, and this loop might lie across a Page boundary. Somehow these matters must be catered for in PIC programs. As with so much in programming, there are diverse opinions on which is the best technique. A useful strategy, for instance, could be 1. Assign a functionality to each of the pages which minimizes CALL and GOTO instructions across page boundaries 2. If possible, provide buffer zones, with no instructions, near page boundaries 3. Write a first pass for the code, ignoring the need to set PCLATH; have it assembled and examine the listing
Everyday Practical Electronics, May 2008
Listing 7.4 org 1024 ;h’400’
org 300 ; h’12C’ TABLE1
addwf PCL,F retlw 10 retlw 11 retlw 12 retlw 13 retlw 14
TABLE4
org 2000
org 400 ; h’190’ TABLE2
addwf PCL,F retlw 20 retlw 21 retlw 22 retlw 23 retlw 24
TABLE5
org 513 ; h’201’ TABLE3
addwf PCL,F retlw 30 retlw 31 retlw 32 retlw 33 retlw 34
4. Determine where CALL and GOTO instructions cross Bank boundaries, and where table calls (or other arithmetic operations on PCL) cross Page boundaries 5. Readjust tables so they are completely contained in a Page 6. Include PCLATH setting instructions where required
addwf PCL,F retlw 40 retlw 41 retlw 42 retlw 43 retlw 44 ; h’7D0’
addwf PCL,F retlw 50 retlw 51 retlw 52 retlw 53 retlw 54 retlw 55 retlw 56 retlw 57 retlw 58
7. Repeat steps 4, 5 and 6 until no further corrections are required. You might have to try again if the process does not converge.
Practicalities In practical terms, manual inspection and iteration during program development is at the very least tedious and time consuming.
At worst, it can be highly error prone. Each time a program is modified, you need to repeat the fix-up process, and on subsequent occasions the chances are that you have mostly forgotten how large chunks of the program work in detail. Alternatively, every relevant instruction that might involve Bank boundaries could be preceded by PCLATH-setting instructions, whether they are needed or not. While it can be argued that it would be cumbersome and consume valuable program memory space to set PCLATH for every such instruction, there is a lot to be said for the brute force approach if programming space permits it, and there are doubts about where Bank boundaries might lie. The use of PCLATH is essential in many larger PIC programs, and it is a command that you should familiarise yourself with through experiment. Perhaps the best advice is to use it in a fashion you feel comfortable with, and which you have proved through experimentation to be reliable. While evolving that technique, remember that you have to keep your wits about you again. The use of extended memory and PCLATH is not suited to demonstration here via a simple program, needing a much larger concept to get stuck into. We hope to bring you an example later in the series.
References PIC16F87x Extended Memory Use, John Becker, EPE June 2001 Using the PIC’s PCLATH Command, John Waller, EPE July 2002 PIC Macros and Computed GOTOs, Malcom Wiles, EPE Jan 2003
EPE BINDERS KEEP YOUR MAGAZINES SAFE – RING US NOW!
This ring binder uses a special system to allow the issues to be easily removed and reinserted without any damage. A nylon strip slips over each issue and this passes over the four rings in the binder, thus holding the magazine in place. The binders are finished in hard-wearing royal blue p.v.c. with the magazine logo in gold on the spine.They will keep your issues neat and tidy but allow you to remove them for use easily. The price is £7.95 plus £3.50 post and packing. If you order more than one binder add £1 postage for each binder after the initial £3.50 postage charge (overseas readers the postage is £6.00 each to everywhere except Australia and Papua New Guinea which costs £10.50 each). Send your payment in £’s sterling cheque or PO (Overseas readers send £ sterling bank draft, or cheque drawn on a UK bank or pay by card), to Everyday Practical Electronics, Wimborne Publishing Ltd, Sequoia House, 398a Ringwood Road, Ferndown, Dorset BH22 9AU. Tel: 01202 873872. Fax: 01202 874562. E-mail: editorial@epemag.wimborne.co.uk. Web site: http://www.epemag.co.uk Order on-line from: www.epemag.wimborne.co.uk/shopdoor.htm We also accept card payments. Mastercard, Visa, or Maestro (minimum card order £5). Send your card number and card expiry date plus Switch Issue No. with your order.
Everyday Practical Electronics, May 2008
53
HandsOn Technology
http://www.handsontec.com
ISP to ICP Programming Bridge: HT-ICP200 In-Circuit-Programming (ICP) for P89LPC900 Series of 8051 Flash μController… …ICP uses a serial shift protocol that requires 5 pins to program: PCL, PDA, Reset, VDD and VSS. ICP is different from ISP (In System Programming) because it is done completely by the microcontroller’s hardware and does not require a bootloader… That the 80C51-based controllers are extremely popular is nothing new, certainly when considering the large number of designs that can be found on the web. The reason may well be the fact that the tools (both hardware and software) that are available for this controller are very affordable and there is an enormous amount of information readily available. In addition, a very active forum provides answers to many questions. One of the most significant features of the P89LPC900 Family is that the core now requires only 2-clock Cycles Per Instruction (CPI). 8051 experts will already know that this used to be 12 or 6 cycles until now. In practice, this means that the crystal frequency can be drastically lowered to achieve the same processing speed as their classic counter parts.
1. INTRODUCTION P89LPC9xx parts (affectionately know as the LPC900 series of micro-controllers) can be programmed 4 ways... 1. 2. 3. 4.
ISP (In-System-Programmed) using the UART of the LPC900. IAP (In-Application-Programmed) .. or "self programmed" by reprogramming the flash under code execution. ICP (In-Circuit-Programming)... using "Synchronous Serial".... Similar to SPI signaling - each data bit is clocked in/out under clock signal control. Parallel Programmer, available in expensive industry grade tools.
ISP Programming is only available for 20, 28 and 44pin parts. IAP is only available once your IAP program has been loaded in to the LPC900 part. ICP -can be used to program all the LPC900 parts. The LPC90x devices can only be programmed using a ICP programming method. In contrast to some of the larger LPC900 family members, the LPC90x devices do not offer other programming methods like Parallel Programming, InSystem Programming (ISP) or complete In-Application Programming (IAP). HOWEVER - ICP requires hardware control/ signaling of the LPC900 to be programmed. In some high-end applications, there may be a need to replace the code in the microcontroller without replacing the IC itself. This article described in detail the operation of the In-Circuit-Programming (ICP) capability which allows these microcontrollers to be programmed while mounted in the end product. To communicate between a PC (running Flash Magic) and the LPC900 Micro-Controller to be programmed an "ICP Bridge" circuit is required as shown in Figure 1.
HT-ICP200
P89LPC900 Target Application Board
Figure 1: Hooking up ICP to the P89LPC900 Application Board
1
Teach-In 2008 Part Eight â&#x20AC;&#x201C; RS232 serial communication, basic use of Timer 1, plus an introduction to ADC JOHN BECKER
I
n this eighth part of Teach-In 2008 we look at two or more PICs communicating with each other. It is a technique that the author has used several times in EPE projects, notably in the Giant LED Message Display and Polyphonium. The technique can also be used when a PIC needs to communicate with a PC that has a serial (COM) port (communication via a USB port is a very different and complex technique and beyond the scope of Teach In 2008). Many, but not all PICs have RS232 protocol serial communication facilities. With the PIC16F62x family, the allocated pins are on Port B RB1 (RX) and RB2 (TX). Other PICs may use different ports and pins. There is a protocol for using the facility, allowing different transmission (Baud) rates to be used, so that synchronicity is maintained between the sender and the receiver, and allowing two-way communication. You will need a second PIC16F628 in order to run the demonstration that we present here. Both PICs run under their own internal 4MHz oscillators. The circuit diagram for the demo and its extra PIC is shown in Fig.8.1, and the necessary breadboard layout is in Fig.8.2. The same program is used in both PICs, load them both with TEACHINH01.hex. Basically, the circuit consists of the PIC and LCD from the demo board, represented in the upper part of Fig.8.1, and used as the receiver. The transmitter is shown in the lower part of Fig.8.1, and consists of the second PIC and a simple value-generator circuit to its right, transmitting information to the demo board, which displays the received value on the LCD. This part will be discussed later on.
Software listing As said, identical software is used in both parts of the circuit. There are two parts to the software, one associated with the transmission and the other with the reception and display. When the software is run, it first checks the status of pin RA2. If the pin is low the software routes to the transmission part, if it is high it routes to the reception part. The pin connections are shown in Fig.8.1.
48
Fig.8.1. Circuit diagram for the PIC to PIC demo The generator circuit, under software control, causes an oscillator to run, repeatedly changing the input status to RA4. The software counts from zero during the oscillatorâ&#x20AC;&#x2122;s transition from logic 0 to the point at which the Schmitt trigger input at RA4 is taken to be logic 1. At this point, the counter stops, and its value is read and transmitted to the receiver circuit. The receiver then displays that value on the LCD. The timing varies from cycle to cycle, so the displayed value keeps
changing between certain extremes. The range of extremes is also controllable by VR2, which affects the rate at which the RA4 value changes from low to high, so changing the basic counting rate.
Setting for RS232 control Immediately before function routing is established, the software is initialised in the normal way, it then enters an RS232 control routine which sets various essential control factors, including the Baud rate. This routine
Everyday Practical Electronics, June 2008
Fig.8.2. Additional breadboard layout for use with Fig.8.1 was originally supplied to EPE by reader Joe Farr when his RS232 PC control article (EPE Serial Interface) was published. The routine is shown in Listing 8.1. It is the SETBAUD routine that is important during the setting up stage. The value associated with the Baud rate is obtained from a quite complicated formula, which takes into account the PIC’s control clock rate (4MHz for this circuit) and which is discussed shortly. That value, 103 at this time, is that required for a 2400 Baud rate. It is placed into the PIC’s SPBRG register, and the TXSTA and RXSTA registers are set with values that enable the PIC’s TX and RX functions. For some reason the SPBRG register is not listed in Microchip’s .inc file, and so this is specified independently with the command during the basic initialisation routine following the CBLOCK section: SPBRG EQU H’99’ This technique for specifying register equates values has not been discussed here before, but you will have seen it occasionally in the Teach In software, and if you’ve examined Microchip’s .inc file. The technique is useful if you wish to allocate a specific register (normally
named by the user) to a specific address. The equated name goes at the far left of the ASM page. It is followed by ‘EQU’ and then the address to which you want to allocate it, in any of the numerical formats. Via FlushRXBuffer, the PIC’s RS232 reception buffer is then cleared to remove any possible previously received data. A return to the main program is then made.
Fig.8.3. Screen dump of TK3's Baud rate calculating facility
Baud rate calculation
Microchip state that it may be advantageous to use BRGH = 1 even for slower Baud clocks, because its equation can reduce Baud rate error in some cases. Transposing the formula when BRGH = 1, we get:
The formula for calculating SPBRG values in respect of Baud rate is quoted in the PIC’s datasheet. It is a bit fiddly to use each time it is needed and the author wrote a short routine for it as part of his TK3 software, written in Visual Basic 6 (VB6). The heart of the routine is shown in Listing 8.2 and could be translated to suit other forms of Basic if desired. The values and other messages are output to screen Labels as part of the main VB6 program. The TK3 display screen is shown in Fig.8.3. Listing 8.3 shows a worked example using Microchip’s formula, and is for a Baud rate of 9600 at a clock rate of 3.2768MHz. Where Fosc is the PIC’s clock rate and X is the SPBRG Value.
Listing 8.1 SETBAUD
BANK1 movlw 103 movwf SPBRG movlw b’00100100’ movwf TXSTA bcf STATUS,RP0 movlw b’10010000’ movwf RCSTA call FlushRXBuffer return
; Configure the baud rate generator ; BRG for 2400 baud from 4MHz, brgh=1 ; In bank 1 ; BRGH = 1(High speed, bit 2) & ASYNC transmission (bit 5) ; In bank 1 ; back to RAM page 0 ; ASYNC reception ; In bank 0 ; Flush the RX buffer in bank 0
FlushRXBuffer movf RCREG,W movf RCREG,W movf RCREG,W return
Everyday Practical Electronics, June 2008
; Flush the RX buffer in bank 0
Listing 8.3 Baud = Fosc / (16 x (X + 1) for BRGH = 1 Baud = Fosc / (64 x (X + 1) for BRGH = 0
X = (Fosc / (Baud x 16)) − 1 Thus for Fosc = 3.2768MHz and Baud = 9600 we get: X = (3276800 / (9600 x 64)) − 1 = (3276800 / 153600) − 1 = 20.333 Only integer (whole number) values can be used, so the calculated SPBRG value is 20. Putting the value of 20 into X of the formula, we get an actual Baud rate of: 3276800 / (16 x (20 + 1)) = 3276800 / 336 = 9752.38 This represents an error of (9752.38 − 9600) / 9600 = 0.015873%, which is immaterial. Following the return to the main program after setting the Baud rate, the PIC’s Timer 1 is initialised. This, and the timer’s use are discussed later. The routing for transmission or reception is then selected. The transmission routine is shown in Listing 8.4. Ignoring for the moment how the values to be transmitted are arrived at, the timer is reset, the Fig.8.1 oscillator triggered and the timer started. When the oscillator’s cycle has completed, the timer is stopped. Now the letter ‘S’ (for Sync) is transmitted via the TXBYTE routine, which is shown in Listing 8.5. The purpose of sending this letter is to minimise the risk of the receiver receiving the value bytes in the wrong order.
49
Listing 8. Public Sub Calculate Click() If BaudIndex 0 Then C Else C If C 0 And C 256 Then BRGH0 actualbaud0 actualbaud0 error0
= (XtalIndex / (BaudIndex =0
error0 Label1.Caption Label5.Caption Label7.Caption Else beep Label1.Caption Label5.Caption Label7.Caption End If If BaudIndex 0 Then C Else C If C 0 And C 256 Then BRGH1 actualbaud1 actualbaud1 error1
=C = XtalIndex / (64 (CInt(BRGH0) + 1)) = Int(actualbaud0 1000) / 1000 = ((actualbaud0 - BaudIndex) / BaudIndex) 100 = Int(error0 1000) / 1000 = SPBRG = & CInt(BRGH0) = Baud = & actualbaud0 = Error & error0 & %
btfss PIR1,TXIF ; is TX Buffer empty yet
= NOT POSSIBLE = =
movwf TXREG ; Now empty character
= (XtalIndex / (BaudIndex =0
error1 Label2.Caption Label6.Caption Label8.Caption Else beep Label2.Caption = NOT POSSIBLE Label6.Caption = Label8.Caption = End If END SUB
64)) − 1
16)) − 1
=C = XtalIndex / (16 (CInt(BRGH1) + 1)) = Int(actualbaud1 1000) / 1000 = ((actualbaud1 - BaudIndex) / BaudIndex) 100 = Int(error1 1000) / 1000 = SPBRG = & CInt(BRGH1) = Baud = & actualbaud1 = Error & error1 & %
Listing 8. MAIN
clrf TMR1L clrf TMR1H bsf PORTA,1 bsf T1CON,0
; reset timer 1 LSB ; reset timer 1 MSB ; set RA1 high to start cap charging ; start timer 1
M2
btfss PORTA,4 goto M2 bcf T1CON,0 bcf PORTA,1
; has cap reached RA4 trigger level ; no ; yes, stop timer 1 ; set RA1 low to discharge cap
movlw ‘S’ call TXBYTE movf TMR1H,W call TXBYTE movf TMR1L,W call TXBYTE
; transmit ‘S’ for sync
call PAUSIT call PAUSIT goto MAIN
; allow time for cap to discharge ; allow time for cap to discharge ; repeat
Listing 8. TxByte nop btfss PIR1,TXIF goto TxByte movwf TXREG return
50
The timer’s MSB and LSB are then similarly transmitted, followed by a brief pause, and the process repeats, until the power is switched off. At the TXBYTE routine a check is first made to see if the transmission buffer is empty:
; TX Buffer empty yet ; No Keep waiting ; Now empty send this character
If it is not empty, the checking continues in a loop until it is. It should be recognised that there is a delay dependent on the Baud rate selected, which determines the rate at which a value in the buffer is transmitted. When the buffer is empty, the new byte to be transmitted is placed into the buffer: send this
Once a value is within the buffer, no further program action is needed for transmission, the PIC automatically takes care of it. First, the PIC’s RCSTA and TRISB registers are set for reception. Then, at R1, a check to see if any data has been received, looping if it has not: R1 btfss PIR1,RCIF ; Check for any RX’d data goto R1 ; Nothing RX’d When it has been received, the data is loaded into W, via o f R R , and a check made to see if the data is ‘S’, the sync command transmitted. If not, the loop repeats. If the data is correct, Port A is toggled to signal to you, via a multimeter if desired, that correct reception has taken place. In theory, of course, it is possible that counter value data could also have the same 8-bit value as the ASCII for letter ‘S’, but the technique reduces the chances of data being received in the wrong order. A better technique using checksums, was discussed by Mike Hibbett in PI n i Jan ’08. Now the two counter bytes are awaited, MSB and LSB, and loaded into W when received. Next, the RCSTA and TRISB registers are set to allow Port B to be used to send data to the LCD: movlw 0 movwf RCSTA BANK1 movlw b’00000000’ ; set TRISB for LCD output movwf TRISB BANK0 The received two-byte value is now digitised and output to the LCD on its Line 1. Each time a fresh batch of data is received, an 8-bit counter is incremented and its value is shown on Line 1 following the TX value. The process then repeats for as long as data is transmitted until the power is switched off in this demo. Data reception is slightly complicated by the fact that both the LCD and the RS232 pins are within Port B. Consequently, a few housekeeping commands are required to ensure correct functioning of the TRISB register, study the main program.
Everyday Practical Electronics, June 2008
i e out
In a real program, rather than ust a demo, it is possible that TX/RX could be interrupted by a fault, such as the TX PIC going off-line or the connecting wires being broken. If this were possible, the use of a time-out would be beneficial. A time-out option can be easily inserted into the reception routines, resetting a timer each time reception is required and incrementing it until data is received. If data is not received within a given period, a termination routine would be entered.
i er
We are also introducing here the use of the PIC16F628’s Timer 1. Unlike the 8bit Timer 0 previously discussed, Timer 1 is a 2-byte (16-bit) counter, with its MSB and LSB held in TMR1H and TMR1L respectively. The PIC on the breadboard uses a software routine which is somewhat similar to analogue-to-digital conversion (ADC). The PIC’s Timer 1 is used to monitor a variable voltage on its pin RA4. It is not a true ADC, as the PIC16F628 does not have the facility, unlike some PICs. It is controlled by register T1CON. The timer can have any one of eight prescale values set to be active via its bits 5 and 4: 11 10 01 00
1:8 1:4 1:2 1:1
The timer is stopped when bit 0 = 0, and started when bit 0 = 1. To select Timer 1 for a prescale value of 1:8 requires the following commands: movlw b’00110000’ ; set timer 1 for ;prescale 1:8, and timer off movwf T1CON To start the timer you simply use the command bsf T1CON,0 and to stop it again bcf T1CON,0 The timer can be incremented from several sources, either internally or externally. It is used in this application so that it is incremented by the PIC’s oscillator, at one quarter of the nominal rate, ie at 1MHz for a 4MHz clock. See the PIC’s datasheet for more information on Timer 1.
aria le olta e detection
The circuit at the bottom of Fig.8.1 is quite simple in operation. Capacitor C1 is initially discharged via diode D1 when PIC pin RA1 is taken low. The timer is simultaneously stopped and reset. When RA1 is set high again, the timer is started and C1 charges up via the wiper of preset VR2 and resistor R1. When the voltage on C1 reaches the threshold of Schmitt trigger input RA4, the PIC regards the voltage on that pin as logic 1. As soon as it does so, it stops the counter and reads its value. RA1 is again taken low and the process repeats.
Everyday Practical Electronics, June 2008
The rate at which C1 charges to the RA4 threshold depends on the voltage supplied by VR2, which can be varied by the user. The timing value varies with the rate of charge. Beware that the minimum voltage VR2 can supply to ensure that C1 charges up adequately is about 3.0V.
techni ues
ADC’s reference is to be set internally or externally (via pins RA2 and RA3). The F87x has two registers which hold the 10-bit converted ADC value. There is a choice: whether or not the first register of the pair (ADRESH) holds bits 9 and 8, with the second register (ADRESL) holding bits 7 to 0 (right ustified). The alternative is for ADRESH to hold bits 9-2 and ADRESL to hold bits 1-0 (left ustified). The selection is determined by the setting of ADCON1 ADFM bit (7), 0 = left ustified, 1 = right ustified. The PIC’s data direction registers (TRISA and TRISE) must also be told which pins are to be used for input in the normal way. An example of doing an ADC once the above requirements have been set is simply:
It may seem that this simple circuit could be made the source for analogue-to-digital conversion (ADC), but in fact it is not reliable enough for that. It is inherently imprecise in its timings, and the rate of charge is not linear with the applied voltage. There are ways in which a PIC such as the PIC16F628 can be made to behave as an ADC, but such matters are a bit complicated and if you need ADC facilities it is better to choose a PIC already with the facility. GETADCVAL bsf ADCON0,GO There are many examples of a ; start data conversion PIC16F87x device’s ADC facility illustratGETADC btfsc ADCON0,GO ed in EPE constructional articles, many of ; is conversion complete them by the author. The software for these goto GETADC designs can be downloaded free via ; no e e a i orne co u . However, movf ADRESH,W it is worth highlighting the general ADC ; yes, get ADC MSB val principle of an example PIC, the movwf REGA1 16FPIC876, even though that PIC is not BANK1 used for this Teach In. Sooner or later you movf ADRESL,W are going to want to use one of the 87x ; get ADC LSB val family, or others that have ADC. BANK0 First, it must be noted that the 876 must movwf REGA0 be set for analogue mode for the ADC to return be used, and which pins are to be used for ADC input, of which the 87x has eight, Here the two bits of the conversion regRA0 to RA5, plus RE0 to RE2. This is ister are stored in user registers REGA1 done with a couple of commands in Bank and REGA0, for later use by the program. 1, in which register ADCON0’s bits 5-3 It should be noted that the 87x holds the hold the port pin selection code. To set all ADRESH register in Bank 0 and the available pins for ADC requires these pins ADRESL register in Bank 1 (this is not the to be set high, B’00111000’. case for all PICS that can do ADC). There is also a choice of conversion You should also be aware that there is a rate which can be set, related to the PIC’s time lag that must be allowed when changclock rate (Fosc), using ADCON0’s bits ing ADC channels within a program. A call 7 and 8, with a code of 00 providing the to a delay routine such as PAUSIT, norfastest rate of Fosc/2. But it must be mally takes care of it. noted that the conversion rate choice See the PIC16F87x datasheet for more must take into account what the Fosc rate information on that PIC’s ADC use, in actually is, as some conversion rates are particular its Figs 11-1 and 11-2 in Section not possible with some combinations of 11.0. conversion code. With an Fosc rate of 5MHz, for instance, the fastest convers to s sion rate is 1.6Ps, requiring a code of 01 As explained earlier, PCs having RS232 (Fosc/8). serial (COM) ports can be used with a PIC, Whether or not the ADC is actually using an RS232 interface chip, such as the active is determined by the setting of ADCON0 bit 0 (ADON), 1 for on, 0 for off. To start the c o nv e r s i o n ADCON0 bit 2 (GO/DONE bit) must be set. It is automatically cleared when the conversion is complete. In addition, register ADCON1 determines a number of factors, such as which pin actually feeds to the internally-multiplexed ADC, and as to Fig.8.4. RS232 interface between PIC and PC whether on not the
51
MAX232. Software for such use was written by Joe Farr for his Serial Interface article. It was written in VB6 and has been used many times in EPE pro ects. Copies of the article are available via the EPE Back Issues department. The software is also available via e e a i orne co u . The circuit for an RS232 PC interface is shown in Fig.8.4.
Reaction i er
There’s room this month to provide you with a Reaction Timer. It’s circuit is shown in Fig.8.5, and the breadboard layout in Fig.8.6. Assemble it and load the PIC with he . When the program is run, the message ‘REACTION TIMER’ is shown on LCD line 2 and LED D2 is turned on. Now press switch S2 to start a random delay. At the end of the delay, LED D1 comes on. As soon as it does, LED D2 is turned off and a timer based on Timer 1 is started. Press switch S1 as soon as you see LED D1 lit. The time between D1 coming on and you pressing S1 is then displayed on line 1, in seconds, to three decimal places. During the time between D1 coming on and you pressing S1, Timer 1 counts at the PIC’s clock rate divided by four every microsecond for a 4MHz clock rate. Each time Timer 1 rolls over, a counter is incremented. When S1 is pressed, The counter value is multiplied by 63356 and added to the timer’s value. The answer is divided by one million and displayed as a seconds count. In this instance, the division is done by simply placing a decimal point in the display at the appropriate position, and omitting the final three digits of the converted decimal value. The delay value is updated in a semi-random fashion while the wait for S1 to be pressed is in progress. Should S1 not be pressed before the counter rolls over, an overflow condition exists and is diplayed on screen; LED D2 comes on again. S2 must be pressed again to restart the process from the beginning. Study the ASM file’s code to see how the whole program operates.
Fig.8.5. Reaction timer circuit diagram
Fig.8.6. Breadboard layout for Fig.8.5
EPE BINDERS
KEEP YOUR MAGAZINES SAFE – RING US NOW!
This ring binder uses a special system to allow the issues to be easily removed and re-inserted without any damage. A nylon strip slips over each issue and this passes over the four rings in the binder, thus holding the magazine in place. The binders are finished in hard-wearing royal blue p.v.c. with the magazine logo in gold on the spine. They will keep your issues neat and tidy but allow you to remove them for use easily. The price is £7.95 plus £3.50 post and packing. If you order more than one binder add £1 postage for each binder after the initial £3.50 postage charge (overseas readers the postage is £6.00 each to everywhere except Australia and Papua New Guinea which costs £10.50 each). Send your payment in £’s sterling cheque or PO (Overseas readers send £ sterling bank draft, or cheque drawn on a UK bank or pay by card), to Everyday Practical Electronics, Wimborne Publishing Ltd, Sequoia House, 398a Ringwood Road, Ferndown, Dorset BH22 9AU. Tel: 01202 873872. Fax: 01202 874562. E-mail: editorial@epemag.wimborne.co.uk. Web site: http://www.epemag.co.uk Order on-line from: www.epemag.wimborne.co.uk/shopdoor.htm We also accept card payments. Mastercard, Visa or Maestro. Send your card number and card valid from and expiry date and the card security code (the last 3 digits on the signature strip) plus Maestro Issue No. with your order.
52
Everyday Practical Electronics, June 2008
HandsOn Technology is a manufacturer of high quality educational and professional electronics kits and modules, uController development/evaluation boards. Inside you will find Electronic Kits and fully assembled and tested Modules for all skill levels. Please check back with us regularly as we will be adding many new kits and products to the site in the near future. Do you want to stay up to date with electronics and computer technology? Always looking for useful hints, tips and interesting offers?
Inspiration and goals... HandsOn Technology provides a multimedia and interactive platform for everyone interested in electronics. From beginner to diehard, from student to lecturer... Information, education, inspiration and entertainment. Analog and digital; practical and theoretical; software and hardware... HandsOn Technology provides Designs, ideas and solutions for today's engineers and electronics hobbyists.
Creativity for tomorrow's better living... HandsOn Technology believes everyone should have the tools, hardware, and resources to play with cool electronic gadgetry. HandsOn Technology's goal is to get our "hands On" current technology and information and pass it on to you! We set out to make finding the parts and information you need easier, more intuitive, and affordable so you can create your awesome projects. By getting technology in your hands, we think everyone is better off We here at HandsOn like to think that we exist in the same group as our customers >> curious students, engineers, prototypers, and hobbyists who love to create and share. We are snowboarders and rock-climbers, painters and musicians, engineers and writers - but we all have one thing in common...we love electronics! We want to use electronics to make art projects, gadgets, and robots. We live, eat, and breathe this stuff!! If you have more questions, go ahead and poke around the website, or send an email to sales@handsontec.com. And as always, feel free to let your geek shine - around here, we encourage it...
http://www.handsontec.com
Teach-In 2008 Part Nine – Watchdog Timer, Sleep and Interrupts, plus simple value converter
JOHN BECKER
T
his month we show you how to use three important PIC facilities – the Watchdog Timer (WDT), Sleep and Interrupts. The purpose of a PIC’s Watchdog Timer (WDT) is to give the PIC a type of protection against becoming stuck in a perpetual loop. This can happen in several ways, but particularly in the event of unforeseen program errors, or waiting for an external event to happen, but which never does (for many and varied reasons, including equipment malfunction). It is also possible for electrical spikes on power lines to cause the malfunction, although it can be argued that the use of a good power supply should be mandatory in situations where this could be an unacceptable problem. In effect, the WDT provides a ‘lastditch’ time-out timer which, if it is allowed to time-out, causes a complete system reset. The idea is that the WDT is set with a prescaled timing value, and then at regular intervals in the main loop of the program, this value is repeatedly reloaded into it, ie it is reset, using the command CLRWDT. Should a problem occur which prevents the WDT value from being reloaded, the WDT will time-out and cause a full program reset. The difficulty of using a WDT in many programs is that when the full reset occurs, any variables which are specifically set to known values at the start of the program will once more be reset to them. This means, for example, that event counters within the program will also be reset. When the existing count value is of importance, rather than use the WDT, the program should be written so that an interrupt (from a switch, for instance) can cause the program to resume running without being reset. However, if it doesn’t matter that the program restarts from the beginning, as in some burglar alarm systems perhaps, then the WDT can be beneficially used. To use the WDT, the PIC has to be set for this function through the Config code. In this case, where the internal 4MHz oscillator is used, the equivalent code for WDT to be turned on is __config h’3F34’, as you will see near the head of the demo program. The rate of WDT time-out is governed by the setting of bits 0 to 2 of the OPTION_REG. The WDT is initially
Everyday Practical Electronics, July 2008
Fig. 9.1. Circuit for WDT and Sleep demos cleared at the same time while still in BANK1: MOVLW b’00001111’ ; allocate prescaler for WDT (bit 3 = 1) ; with slowest timer 1:128 (bits 0-2) MOVWF OPTION_REG CLRWDT ; clear watchdog timer BANK0 The main part of the program, starting at TESTON, is shown in Listing 9.1. The call to PAUSIT is to make the count rate more visible. Assemble the circuit as shown in Fig.9.1 and Fig.9.2. Switch S1 is used for this demo. Load the program’s hex file, TEACHINJ01.hex, and run it.
Watch it! Observing the count on the LCD, you will see that the count never really gets very high because WDT is not being reset, and so timing out and resetting the program. However, if you periodically press switch S1, WDT is reset and the count continues upwards. Should you not press S1 fast enough, the WDT will timeout and restart the program from the beginning, causing the count to be reset to zero.
Fig. 9.2. Breadboard layout for Fig.9.1 The WDT timing period can be changed in the same way that we set the timing prescaler for the TMR0 real-time clock, ie using bits 0 to 2 of OPTION_REG. Bit 3 of OPTION_REG must always be set so that the prescaler is allocated to the WDT.
51
Listing 9.1 TESTON
TSTOFF
incfsz COUNTER0,F goto TSTOFF incfsz COUNTER1,F goto TSTOFF incfsz COUNTER2,F goto TSTOFF incf COUNTER3,F
; inc Counter value ; inc Counter value ; inc Counter value ; inc Counter value
movf COUNTER0,W movwf REGA0 movf COUNTER1,W movwf REGA1 movf COUNTER2,W movwf REGA2 movf COUNTER3,W movwf REGA3 call BIN2DEC call LCD1 bsf RSLINE,4 call SHOWDIGIT1 btfsc PORTA,4 CLRWDT call PAUSIT goto TESTON
; repeat the procedure
call SHOWIT incfsz COUNTER0,F goto MAIN
; (decimalisation and display) ; inc Counter value, is it = 0? ; no
BANK1 movlw 1 movwf TRISB BANK0
; yes ; set RB0 for input
MOVLW b'00010000' MOVWF INTCON SLEEP BCF INTCON,1 BANK1 clrf TRISB BANK0 incfsz COUNTER1,F goto MAIN incfsz COUNTER2,F goto MAIN incf COUNTER3,F goto MAIN The WDT cannot be disabled from within an operational program. It can only be turned off from the PIC configuration command. An independent RC oscillator is used by the WDT and its timing is unaffected by the frequency of the external oscillator that controls the rest of the PIC. Try setting different values into bits 0 to 2 of OPTION_REG and observe the count’s value on the LCD in respect of the WDT time-out.
Sleep SLEEP mode sets the PIC into a very low current power-down mode. This can be useful if the PIC is monitoring or controlling something at a very slow rate. In this situation, there are powersaving advantages if the PIC can be put to sleep during periods when it is not required to perform.
52
MOVLW b’00000111’ ; set bit 6 for interrupt on falling edge of RB0 change MOVWF OPTION_REG ; port B pullups on, bit 7 = 0 Bits 0 to 2 of OPTION_REG being set high is to suit TIMER1, which is used in connection with the LCD, as explained in a previous part. The second point is that TRISB must be set first for the use of the LCD output, and then, once the PIC is asleep, TRISB,0 is set so that RB0 can behave as an input for S2. Once S2 has been pressed, TRISB is again set for LCD use with TRISB,0 being cleared. The third point is that bit 1 of the INTCON register has to be cleared when the PIC is reawoken. It is set by the action of the PIC being told to sleep.
Listing 9.2 MAIN
rising edge of the switch press if bit 6 were set to 1. The current arrangement suits the fact that PORTB pull-ups are on, so that RB0 is normally held high:
; set bit 4 to enable external interrupt ; now go to sleep and wait till RB0 switch ; is pressed ; clears ext interrupt flag after end sleep ; set PORTB for LCD use ; inc Counter value ; inc Counter value ; inc Counter value
The PIC can be awoken from SLEEP by a WDT time-out or through an external interrupt. The program which illustrates the latter is TeachInJ02.ASM, as shown in part in Listing 9.2. The circuit is the same as that for the WDT demo, but uses switch S2 on pin RB0. Load the program and run it. The program increments a 4-byte counter and outputs the value to the LCD. At each roll-over to the second byte the program is told to SLEEP. It can only be awoken by pressing switch S2, connected to PORTB RB0. Whereupon, the PORTB count resumes, until again it rolls over, falling asleep once more. There are several important things to note. First, the ‘awake’ call by S2 operates on the falling edge of the switch press, as set into the OPTION_REG by its bit 6 being set to 0. It would operate on the
Interrupts An Interrupt, as the term implies, literally is an ‘interrupt’ to the program, causing it to stop what it is currently doing, and perform another action or set of actions, returning to where it left off when the interrupt occurred. Interrupts can be set to occur from several sources, such as a switch or from a trigger pulse generated by another electronic circuit for example. There are many other interrupt possibilities, as shown in datasheet Fig.14-14 (P104) and Table 14-8 (P106). The function of the bits of the INTCON register are given in its datasheet Table 4.3 (P24). Also see the datasheet for the PIR1 and PIE1 register bit functions. There are countless situations where interrupts can be put to good use. Let’s examine the switch controlled one, and then a timer controlled interrupt. First, the address to which the program must jump when interrupted has to be specified. This is where the opening ORG 4 statement now comes into its own. Following that statement, and prior to the ORG 5 statement, the jump address is inserted. Let’s call the jump address ISR, Interrupt Service Routine. So, at the beginning of the program listing we make the following statements: ORG 4 GOTO ISR ORG 5 Since the program, once triggered by an interrupt, automatically jumps to the program address stated, we can simply set up a holding routine which waits until the interrupt occurs, and then the routine specified at the interrupt address is performed. We could actually allow the entire program to be performed without using a holding routine, jumping to the specified routine when the interrupt does occur. This is tricky, though, and can be dangerous to the correct operation of the main program, as will be seen shortly. Allowance has to made for a particular operation to be completed before the interrupt routine is performed. The use of a holding routine can be as simple as: HERE nop goto HERE
Everyday Practical Electronics, July 2008
The program would normally be constantly looping through the two commands NOP and GOTO HERE, waiting for an interrupt to occur. On its occurrence, the loop would be exited, and a jump made to the routine at ISR. Obviously, at the end of the routine caused by the interrupt, a return to the program point from where the interrupt jump was made must be specified. There is a command which is used for this purpose, RETFIE. If we want an external source to generate interrupts, the usual pin used for this purpose is PORTB RB0, designated in the pinout diagram as RB0/INT. (Logic level changes on PORTB RB4 to RB7 are other possible interrupt sources.) To use RB0 as the interrupt source, INTCON bit 4 (INTE) must be set, as follows: MOVLW b’10010000’ MOVWF INTCON INTCON bit 7 (GIE) must, as shown, also be set to enable the global interrupt function. All interrupt bits are named by Microchip and equated as such in the initialising commands brought in via Microchip’s .inc file. GIE stands for Global Interrupt Enable.
ternal nterrupt Suppose now that we want an external interrupt on RB0 to cause PORTA to be incremented. Each time this interrupt occurs, the jump from the holding loop is performed as before. However, it is now INTCON bit 1 (INTF) which is set on the interrupt and has to be cleared before returning to the holding loop, ie BCF INTCON,1 (or bcf INTCON,INTF). Any interrupt monitoring flag must be cleared before that interrupt can occur again.
Having illustrated the use of a switch controlled interrupt, we now show the use of the PIC’s TMR0 timer as the interrupt source. That function is in program T A I J0 .as and its main part is shown in Listing 9.4, which is a modification of the program shown in Listing 9.3. The timer is set to its slowest rate via OPTION_REG. The interrupt enabling bits required are GIE and T0IE, as set into INTCON. When the Fig. 9.4 Breadboard layout for Fig.9.3 ISR routine is called, the TMR0 overflow the interrupts, in addition to any other bits flag bit (T01F) must cleared before that required for an interrupt to be enabled. It is interrupt can be responded to again: bcf possible that at the moment of wishing to INTCON,2 (or bcf INTCON,T01F). disable the interrupts, however, that an interrupt could be in the process of occurInterrupt c nte t pr le ring. This would result in the disabling There is a significant problem when command not taking effect. To ensure that using interrupts if program registers are all interrupts are fully disabled (except being updated when the interrupt occurs. WDT), the follow routine can be used: The interrupt could adversely upset the flow of the update. This can be avoided by DISABL BCF INTCON,GIE a simple technique in the ISR routine. BTFSC INTCON,GIE Imagine that we’re just entering the ISR: GOTO DISABL the main program loop has been interrupted. This can happen between any two instrucThe main part of the program is shown in tions; exactly where is just a matter of Listing 9.3. chance depending on exactly when the
Listing 9.3
STARTIT
ORG 0 goto STARTIT ORG 4 goto ISR ORG 5
; reset vector
clrf PORTA clrf PORTB movlw 7
; clear PORTA’s outputs if any ; clear PORTB’s output if any ; needed by some PICs, including PIC16F628 ; so that PORTA is treated as digital port
movwf CMCON BANK1 clrf TRISA movlw b'00000001' movwf TRISB clrf OPTION_REG BANK0 MOVLW b'10010000' MOVWF INTCON
Fig.9.3 Circuit for the Interrupt demo The circuit needed is shown in Fig.9.3. The interrupt is generated using switch S1. Assemble the breadboard as shown in Fig.9.4. Load and run T A I J0 .he which illustrates this external interrupt. Since the switch used may be a low-cost type, it is possible that switch-bounce will cause slightly erratic behaviour of the LEDs. It should become clear, however, that the count is basically incremented when the switch is pressed, not when it is released. If a signal generator is connected to RB0 (via a 10k resistor) in place of the switch and monitored on a scope, the triggering edge should be obvious. The signal generator most produce clean 0V to +5V pulses. As you have seen, INTCON bit GIE (7) is used for enabling (1) and disabling (0)
Everyday Practical Electronics, July 2008
HERE
nop GOTO HERE
TEST
movlw b'11111110' movwf PORTB goto START
ISR ISR2
incf PORTA,F btfsc PORTB,0 goto ISR2 bcf INTCON,1 RETFIE
; interrupt vector address ; PIC program memory location at which to start
; set for Bank 1 ; PORTA as output ; RB0 as input ; PORTB pull-ups on (bit 7 = 0) ; enable GIE (bit 7), RB0 change (bit 4)
; inc LED count ; wait switch release ; clear RB0 interrupt flag
53
Maths c n ers n t l
Listing 9.4 BANK1 clrf TRISA clrf TRISB movlw B'00000111' movwf OPTION_REG BANK0 MOVLW b'10100000' MOVWF INTCON START
nop GOTO START
TEST
movlw b'11111111' movwf PORTB goto START
ISR
incf PORTA,F bcf INTCON,2 RETFIE
interrupt ocurs. Suppose the interrupt actually happened between the two instructions: B1 xorwf COUNT,W (interrupt occurs here) B2 btfss STATUS,Z The main program has just done an Exclusive-OR of COUNT with W (which holds a value of 10 from the previous instruction MOVLW 10), and is about to go on and test the Z flag in the STATUS register to see if the result was zero (ie COUNT = 10). But in between the ISR will run, and this does an INCF ICOUNT,F instruction. This will overwrite the Z flag. So when the ISR exits, and the main program resumes at the instruction labelled B2, that Z test will be invalid. Therefore, the ISR must save anything before it changes it, and restore it before it exits. The bits and pieces that a program uses as working states are often referred to as its Context, and so the preamble and postamble in the ISR are called Saving and Restoring Context. The most important items of Context on a PIC are the various flags in the STATUS register, and the contents of the Working register, W, but there may be others. If the ISR uses indirect addressing for example, then it will need to preserve FSR. The preservation of PCLATH may also become important. The value in the W register can readily be stored, but the Z flag is a problem. Recall that a MOVF instruction could affect the Z flag in the STATUS register, so it cannot be used as part of a context-saving routine. However, the SWAPF instruction does not affect STATUS, so the situation using that instruction is unambiguous. But, of course, STATUS is actually stored in SAVES, with its nibbles reversed. Consequently, on exit the nibbles must be reversed again before being put back into STATUS. Once W and STATUS have been safely stored, then it’s easier to save any other Context items that may need preserving. This is because W and STATUS can now be changed, so there are no constraints on which instructions may be used. So, for example, to additionally save FSR, the following sequence could be used:
54
; set for Bank 1 ; PORTA as output ; RB0 as input ; pullups on (bit 7 = 0), TMR0 slowest rate ; enable GIE (bit 7), TMR0 overflow (bit 5)
; inc LED count ; clear TMR0 overflow flag
ISR
MOVWF SAVEW ; save W SWAPF STATUS,W MOVWF SAVES ; save STATUS MOVF FSR,W ; OK to use MOVF and change STA TUS here MOVWF SAVEF ; save FSR
(body of the ISR goes here) POP
movF SAVEF,W
swapf SAVES,W movwf STATUS swapf SAVEW,F swapf SAVEW,W retfie
; restore FSR movwf FSR ; restore STATUS ; restore W
The same would apply to saving PCLATH, and to any other register that also needs to be preserved. Note that the preservation registers SAVEW, SAVES and SAVEF are usernamed registers equated at the head of the program in the usual way.
Space this month allows us to present you with a design that provides conversions between hexadecimal, decimal and binary maths formats. Although PIC assembly programs allow you to specify values in any of these three formats, it can be useful to know how one format translates to another. TK3 has such a conversion program available as part of its suite of routines. The design presented now is a simpler version of that, assembled using the components you have been using during this series. The circuit diagram and its breadboard layout are shown in Fig.9.5 and Fig.9.6. Assemble the layout and load the PIC with T A I J0 .he . Switches S1 to S4 change the four nibbles of a 2-byte hex value from left to right, incrementing the value between the 16 values 0-9, A-F. Having reached 15 (F) the value rolls over to 0 again on the next increment. The hex value is displayed on LCD line 1 LHS, prefixed by ‘H’. The total hex value is then converted to decimal and displayed to the right of line 1. Then follows a conversion to a 16-digit binary value, displayed on line 2. The process repeats for as long as the respective switch is pressed, but at a rate slow enough to be read easily on the LCD. Referring to Listing 9.5, the incremented hex digit values aquired in the routines starting at DIG0 are each held in their own register, HEX3 to HEX0. The hex display routine reads the decimal value held in each register (at OUTHEX) and calls a table which returns the symbol (0-F) associated with that value, and sends it to the LCD. When the full hex value has been displayed, the four hex digits are combined into two registers COUNT1 and COUNT0, using the SWAPF and IORWF commands (at HEXDEC). The COUNT values are then converted to decimal and displayed. The binary display routine is at HEX2BIN. Here the two COUNT values are rotated left 16 times so that their LH bit rotates into the Carry flag (as previously discussed). The status of the Carry flag is
Fig.9.5. Circuit for the maths conversion tool
Everyday Practical Electronics, July 2008
Listing 9.5 (Continued) OUTHEX
call HEXDEC call HEX2BIN
Fig.9.6 Layout for Fig 9.5 then extracted, ORed with 48 to produce its ASCII symbol and sent to the LCD. Examine the listing to follow the logic. See the ASM file for the full details. To show the HEX and binary values of a decimal number (up to 63355) press the switches until the required decimal value is shown and then read the other two values shown, likewise for finding what a binary value is in HEX and decimal. Intelligent use of the switches is required! If you overshoot a value, just keep any switch pressed to cycle through the digit values again.
call PAUSIT2 goto DIG0 HEX2BIN
call LCD21 bsf RSLINE,4 movlw 16 movwf LOOP
HEXDEC
swapf HEX3,W iorwf HEX2,W movwf COUNT1 movwf REGA1 swapf HEX1,W iorwf HEX0,W movwf COUNT0 movwf REGA0 clrf REGA2 clrf REGA3 call BIN2DEC call SHOWDIGIT5 return
HEX2BIN2
rlf COUNT0,F rlf COUNT1,F movf STATUS,W andlw 1 iorlw 48 call LCDOUT decfsz LOOP,F goto HEX2BIN2 return
e erence Programming PIC Interrupts, Malcolm Wiles, March and April 2002. A detailed feature based on the PIC16F84 and PIC16F87x devices.
Listing 9.5 ; TEACHINY01.ASM 17FEB08 - TEACH IN 2008 PT9 goto OUTHEX DIG0
movf PORTA,W andlw 15 btfsc STATUS,Z goto DIG0 clrf LOOP
DIG4
btfss PORTA,0 goto DIG3 incf HEX3,F bcf HEX3,4 goto OUTHEX
DIG3
btfss PORTA,1 goto DIG2 incf HEX2,F bcf HEX2,4 goto OUTHEX
DIG2
btfss PORTA,2 goto DIG1 incf HEX1,F bcf HEX1,4 goto OUTHEX
DIG1
btfss PORTA,3 goto DIG0 incf HEX0,F bcf HEX0,4
Everyday Practical Electronics, July 2008
call LCD1 bsf RSLINE,4 movlw 'H' call LCDOUT movf HEX3,W call MESSAG2 call LCDOUT movf HEX2,W call MESSAG2 call LCDOUT movf HEX1,W call MESSAG2 call LCDOUT movf HEX0,W call MESSAG2 call LCDOUT movlw ' ' call LCDOUT
55
HandsOn Technology
http://www.handsontec.com
USB-RS232 Interface Card: HT-MP213 A compact solution for missing portsâ&#x20AC;Ś Thanks to a special integrated circuit from Silicon Laboratories, computer peripherals with an RS232 interface are easily connected to a USB port. This simple solution is ideal if a peripheral does not have a USB port, your notebook PC has no free RS232 port available, or none at all ! After a slow and faltering start, the USB port has become commonplace on PCs, to the extent that the latest GHz machines have just one RS232 port left, or none at all. The compact USB-RS232 interface described in this article allows your good old RS232 peripherals (printer, programmer system, etc.) to be hooked up to a USB port. The free driver programs for Win 2000/XP, Linux and Apple Macintosh make the interface virtually transparent, enabling the USB port to behave like a regular COM interface. The driver and the conversion chip from Silicon Laboratories allow a full serial data link to be set up on a 9-way RS232 connector, including all handshaking signals.
1. THE SILICON LABORATORIES CP2103 SYSTEMS OVERVIEW The CP2103 is a highly-integrated USB-to-UART Bridge Controller providing a simple solution for updating RS232/RS-485 designs to USB using a minimum of components and PCB space. The simplified block diagram of the CP2103 is shown in Figure 1 and the pin assignment, in Figure 2. Royalty-free Virtual COM Port (VCP) device drivers provided by Silicon Laboratories allow a CP2103-based product to appear as a COM port to PC applications. The CP2103 UART interface implements all RS-232/RS-485 signals, including control and handshaking signals, so existing system firmware does not need to be modified. The device also features up to (4) GPIO signals that can be user-defined for status and control information. Support for I/O interface voltages down to 1.8 V is provided via a VIO pin. In many existing RS-232 designs, all that is required to update the design from RS-232 to USB is to replace the RS-232 level-translator with the CP2103. Silicon Laboratories has taken care of the PC side of things by supplying royalty-free Virtual COM Port (VCP) device drivers. If you've ever used a PC RS-232-to-USB converter, you know that it looks like a standard COM port to the PC and its applications. The VCP device driver also pretends to be a standard COM port. That means that we can use our newly acquired microcontroller USB interface to communicate with a Tera Term Pro terminal window on a computer just as if we were using RS-232 hardware on the embedded side.
2. HT-MP213 USB-to-RS232 CONVERTER BOARD The HT-MP213 is designed to transition a piece of hardware from an RS-232/485 interface to a USB interface. We were attracted to the CP2103 because of its skinny schematic diagram. If we believe what the CP2103 datasheet schematic is telling us, it doesn't require any external resistors or crystals to bring a fully compliant USB 2.0 interface to life. The silicon encapsulates a level 2.0 full-speed function controller, transceiver, EEPROM, oscillator, and UART in a tiny QFN-28 package. The internal EEPROM is used for storing vendor-specific information in commercial applications. If we find that we need to access the EEPROM, there is easy access and programming via its USB interface.
1
Teach-In 2008 Part Ten - Examining a program’s construction, a game of Dominoes, plus LCD symbol creation
JOHN BECKER
W
E have now reached a point where it is worthwhile discussing a practical full-length program and part of its construction. It illustrates a variety of concepts to which you have been introduced earlier, plus futher information on alphanumeric LCD use, with particular regard to creating your own display characters. The program is for the author’s Mock Dominoes self-entertainment game (previously unpublished) in which the user plays against a PIC, with moves displayed on an LCD. The circuit diagram and breadboard layouts are shown in Fig.10.1 and Fig.10.2. The program is too long to be shown here, and only the occasional extracts will be discussed. The full program is in TeachInX01.asm, available in the usual way from our website (via www.epemag. wimborne.co.uk).
Description Referring to Fig.10.1, the circuit consists of the PIC and LCD on the Teach In 2008 Demo PCB, and four switches on the breadboard. Some of the switches have a multiple function, as will become apparent. When the program is run, the usual initialisation procedures take place. There then ensues a routine in which the two numeric sides of dominoes are created. At the moment, they are represented by numbers 0 to 6 in the standard numeric form. We shall illustrate later how they can be replaced by LCD symbols representing the dots (‘pips’) on a normal domino. The game is limited to seven domino tiles for each player, you and the PIC. Originally, the author used QBasic to simulate the requirements for creating the 28 possible different domino faces in a normal set. In passing, it is worthwhile commenting that modern domino sets can be comprised of 28, 55, 91, 136 or 190 tiles. They are known respectively as Double 6, Double 9, Double 12, Double 15 and Double 18 sets. In mathematical tilings, the word domino often refers to any rectangle formed from joining two squares edge to edge. The word is derived from the Latin dominus, meaning
46
Fig.10.1. Circuit for Mock Dominoes lord or master. The oldest domino sets have been dated back to around 1120, possibly of Chinese origin. General information on dominoes can be found at http:// en.wikipedia.org/ wiki/Dominoes. The Basic requirements were translated into assembler for the PIC program. The author often uses QBasic (or Visual Basic) to simulate the logic of a complex routine before translating it into PIC assembler. The QBasic routine is shown in Listing 10.1.Itproducesallthe possible permutations of the domino face sides from 0 (blank) to 6. The routine is Fig.10.2. Breadboard layout for Fig.10.1
Everyday Practical Electronics, August 2008
Listing 10.1 DIM tile (28) FOR FOR
b
0 CLS
c 0 TO 6 a c TO 6 tile (b) LTRIM (STR (c)) LTRIM (STR (a)) PRI T tile (b) b b 1 XT PRI T XT c PRI T b
readily translatable for running through other forms of Basic. The equivalent PIC routine is in the main program at label Tilesetup.
If you are familiar with dominoes, you will know that the tiles can have their sides swapped over, allowing ‘16’ to be reversed to become ‘61’, for example. Consequently, it is not necessary for a separate ‘61’ tile to exist when there is already a ‘16’. ach tile side is stored as one nibble (4 bits) of a byte (8 bits). Thus, one byte holds the information for a single tile. PICs can be told in which order they should hold their nibbles, with the command SWAPF,F, where ‘F’ is the address of the le whose nibbles are to be swapped. The created tile value storage registers are allocated to be in PIC Bank 0, with an address immediately following other CBLOC allocated register addresses, commencing at TIL 0 (the other 2 tiles are not speci cally mentioned as they are never called by name, but register space is allowed for them.
Initially, who starts the game is also subject to a randomised choice, depending on the unspeci ed setting of START R bit 0, ie bit 0 is used as a ag. (Remember that registers can can take on any random value at power switch on.) The value 0 represents you, whereas 1 represents the PIC. Assuming that the starter is the PIC, it scans its available tile values until it nds a double-sided face (in a normal domino game, the starter usually chooses the highest value of double not so here for the PIC). The choice of double is displayed on LCD line 2, at the left. The byte value is also stored to an incrementing storage register area (commencing at LCDStore0) in Bank 1 at h’C0’. This stores all user or PIC selected choices in order as the game progresses. When writing the program, the author ensured that intentionally allocated registers (via the Q instruction) started at addresses which would not cause an overlap in register allocation. e then only needed to specify the rst address in each group and did not need to name each address in that group. The use of commands FSR and I DF then allows ready access to any address in a group. ote in the ASM le how the value placed into FSR explicitly speci es the Bank as well as the register within it (ORing the register value with 128 for Bank 1, omitting the 128 OR for Bank 0).
Random routine
Switch selection
aving created the 28-tile set, a randomising routine is used to allocate seven tiles to each player, ensuring that no repeats of any tile are produced. This is done by placing ‘xx’ into the used byte, with the software ignoring any value of ‘xx’. A simple randomising routine is used and is similar to the one used earlier in the series when dice throws were being simulated. It is not totally random, but is good enough for the current process. (A more sophisticated randomising routine is described next month.) Randomising here simply entails adding a primary number ( in this case) to a counter each time the randomising routine is accessed. The value of the counter is then read and restricted to values below 32 before the tile selection choice is made according to the value held in the counter. Values greater than 28 are ignored. At the end of the full selection the unused tiles are also ignored in this game. The selected tiles are stored in registers in Bank 1, commencing at h’60’ for you, and at h’A0’ for the PIC. our selected tiles are displayed on LCD line 1. Those for the PIC remain hidden.
When it is your turn to make a tile selection, you use switch S2 to move the highlighted double cursor across the double-byte values. Pressing S1 moves the cursor back. A single press of the switches is required for each move, holding down the switch to progressively move the cursor has been inhibited. There is a brief pause between releasing a switch and when it can be pressed again, to prevent switch bounce. ote in the switch selection routine how a holding loop is used if no switch is pressed. In another program, this might allow the software to go off and do something else while a switch press is awaited. When a highlighted tile has the correct face (either side) to match the right hand face of the last tile shown on line 2, press S3 to select it. It is automatically turned to face the correct way on line 2 if the order is wrong. Following selection via S3, the tile is renumbered to ‘xx’ so that you cannot use it again (as said, the software ignores any ‘xx’ tile face and does not allow its selection). The PIC then tries to nd a face value which matches the right hand side of the tile just selected.
The permutations produced are 00 01 02 03 04 05 06 11 12 13 14 15 16 22 23 24 25 26 33 34 35 36 44 45 46 55 56 66
Everyday Practical Electronics, August 2008
If at any time you do not have a tile which can be played, press S4 to ‘knock’ in the traditional domino fashion. This sets a ag which is cleared when a tile can be played, by either you or the PIC. When a ‘knock’ is made, the other player then tries to nd a suitable tile. If it is the PIC that cannot nd a tile, then it makes an equivalent ‘knock’ and the display on line 2 remains the same, apart from displaying the current ‘knock’ value at its far right. If neither player has a playable tile, the ‘knock’ ag is not cleared and the ag value increments. After four ‘knocks’ the software knows that the game cannot be taken further. It then calculates how many tiles each player has successfully played and shows the results on line 1, with the quantities pre xed by ‘ ’ and ‘P’ respectively, followed by the indication of who has won. If the tile counts are equal, the game is a draw and the winner is shown as ‘X’. The counters’ tile use monitoring is incremented in BCD so that there is no need to use a binary-to-decimal routine before the respective value can be displayed meaningfully. Once the winner has been declared, switch S1 can be pressed to start another game. The program loops and effectively ‘shuf es’ the tiles while reallocating a further seven to each player. ou then play the next game in the same way as the rst. The player who won the previous game now becomes the one to nd the starting double. If a draw exists, the choice of starter is made randomly. When several games are played consecutively, no record is kept of who has won the most. Such matters are left to you and a pen and paper ote how during the game, the played tiles display is truncated to only show a maximum number of tiles, ignoring the earlier ones if there are too many to show on a single line.
LCD cursor control Throughout the game, the LCD cursor is turned on when you are the one to select a tile, but is otherwise turned off. The two commands that control this function are movlw b’00001101’ display on, cursor underline off, cursor blink on call LCDLI and movlw b’00001100’ display on, cursor underline off, cursor blink off call LCDLI ote that any command that is sent to the LCD is always made via the LCDLI subroutine. Two tile faces have to be highlighted simultaneously, and two cursor position addresses are alternately sent to the LCD, rapidly moving the highlight back and forth across a double pair by repeatedly calling routine S L CTC RSORVAL while a switch press is awaited S L CTC RSORVAL bcf STAT S,C rlf S L CTLOOP,W iorlw b’10000000’
4
is turned on. The selection is stored in the EEPROM for use the next time S1 is pressed when the power is switched on. The choice of display type alternates on each such occasion. The value is always read from the EEPROM each time the program is switched on. The LCD has 16 bytes available in its character generator, which can be programmed to hold symbols other than those normally provided. These are held in LCD locations 0 to 15 (see Table 3 in the Using Alphanumeric LCDs article referred to previously in the series for a list of the character generator’s Fig.10.3. Flow chart for the game symbol locations). Display command values between 0 and 15 cause the usercall LCDLIN generated symbols to be displayed in the bcf STATUS,C same way as when you use values to access rlf SELECTLOOP,W symbols at the normal character locations iorlw b’10000001’ (32 upwards). Throughout the eac n series up to this call LCDLIN point, you have been displaying the LCD’s return alphanumericcharacterviatheDisplayAddress command that is part of the LCD initialisation SELECTLOOP holds the address of the routine. To write your own symbols into the tile to be highighted, which is repeatedly Character Generator RAM locations (0 to swapped between the LCD addresses of 15), the CG RAM-use command must first be the two sides of the tile selected. The LCD given, via LCDLIN. The datasheet shows all cursor address is basically twice that of the commands available for a standard 2-line the tile register address, hence the two alphanumeric LCD. commands RLF SELECTLOOP,W. It is the The CG RAM selection command is value of the SELECTLOOP bit 0 held in W b’1AAAAAAA’, where the ‘A’s indicate the which determines the LCD address which is to be highlighted. CG RAM address selection. The selection is made by setting the LCD address you want to write to into ‘W’, and then calling Tile face type LCDLIN. When writing symbol data to the As things stand so far, the values are CG RAM, eight writes to it are required shown numerically. The facility to show to form a complete symbol. The CG RAM them as traditional dots (or ‘pips’) has address is automatically incremented with been provided. The choice of display type each write, thus you only specify the first can be made when switch S1 is pressed address to which you wish to start writing. and held pressed while the PIC’s power
Symbol creation To create a symbol, you draw a squared map of the pixels that make up the symbol (five horizontally and eight vertically). The maps required for the seven domino faces are shown in Fig.10.4. Note that line 8 is reserved for underline cursor use – the main character symbol is in the first seven lines. Below each map are the logic values of each line. A ‘1’ represents a pixel which is to become active, and ‘0’ for one which is not. The values are shown in 5-bit binary logic. To suit them for use in the PIC program, simply add another three zeroes at the beginning of each 5-bit line and terminate the value with another apostrophe, e.g. b’00010001’. Examine the ASM file and you will see all seven domino faces represented in the table at label CHRTABLE. The binary values are preceded by ‘RETLW’ to allow the table to be called and for a return to the calling point to be made with the specified value held in ‘W’. The table starts at program address (ORG) h’400’. When calling the table, you must first set a suitable PCLATH value as it is not in the normal first 256 program locations. The table is then accessed via a loop which allows the table values to be ‘returned in W’. The program’s routine for sending symbol data to the CG RAM is shown in Listing 10.2. Since seven domino symbols are required, the loop is set to read and send 56 values to the CG RAM. Note that the CG RAM is volatile, and so its programmed data is lost when power is switched off, and hence the CG RAM programming routine has to be repeated each time the PIC and LCD are turned on again. Once the CG RAM has been programmed, the symbols can be displayed by writing to the required display address (between 0 and 15) in the normal way. However, the numerical values written through LCDOUT must be no greater than the userprogrammed CG RAM symbol addresses (unexpected symbols will probably appear if you use a greater value). Consequently, when displaying the symbol, the value sent via LCDOUT is not ORed with 48 to convert it to the equivalent ASCII numerical form when numbers are sent for display. The value simply specifies the CG RAM’s address location at which the symbol is held. In the program the command IORLW 48 is bypassed when the user created symbol display flag (GRAPHIC bit 0) is set. It should be noted that after finishing writing to CG RAM, a Display Address, such as that made via call LCD1 plus bsf RSLINE,4 must be sent to return the LCD to normal display mode.
More to think about
Fig.10.4. LCD maps for the Domino faces
48
It is worth experimenting with the commands shown in the LCD command codes table, as there are other display control possibilities available. Ignore the Function Set option, otherwise you could lose control of the LCD until after switching power off and on again. The functions available through this option are partly related to the way that LCD is wired to the PIC.
Everyday Practical Electronics, August 2008
Listing 10.2 C ARCT
C R
movlw b’01000000’ call LCDLI bsf RSLI ,4 clrf LOOPTA
set rst address for CG RAM write
movlw 4 movwf PCLAT
Set for sub-page 4
Stage-by-stage
movf LOOPTA,W call C RTABL call LCDO T incf LOOPTA,F movf LOOPTA,W xorlw 56 btfss STAT S, goto C R clrf PCLAT return
get symbol data send to LCD CG RAM
clear PCLAT
ORG ’400’ (C RTABL goes here) ou might also care to think what routines would need to be added and or changed to allow two human domino players to play together. Some aspects would be simple, but others might be more complex. And a couple of challenges there are two minor bugs in the program. The rst is that when selecting the rst tile pair on LCD line 1, it is sometimes necessary to move the cursor to the second pair and then back again before the rst pair can be selected. Second, the cursor position sometimes skips a pair to the next one. Can you x these bugs
A few helpful notes During this series we have provided you with suf cient knowledge about the PIC16F628 to enable you to now write your own programs for your own purposes. ou should be aware, though, that there are various aspects of the PIC16F628 that we have not described. Many of them the author has never used. In due course, you may nd aspects that are useful. Armed with knowledge about the PIC16F628, you now have a pretty good understanding of the basic requirements for programming any PIC microcontroller. It should be strongly noted, however, that there are other families of PICs in which some aspects are treated differently to the PIC16F628. Whatever PIC you choose to use, always obtain its datasheet before using it. As said previously, datasheets can be downloaded free from Microchip’s website. Always remember that users of our Chat Zone are incredibly knowledgeable about many things, and it’s always worth asking there about any matters which may pu le you.
Programming To the uninitiated, it may seem that a software programmer simply sits down and writes all the commands in a single operation. If only it were that simple Before a single line of code is written, there is a great deal of thought involved about the overall objective and how each step on the
a simple example is given in Fig. 10.3, but created in retrospect rather than prior to the program being written). ou will also nd examples of them in Microchip’s application notes. It has to be said, though, that even in those, which are full of program listings, ow charts are not widely used. Mike ibbett also looked at the subject in PIC n’ Mix.
way to achieving it might be performed. Part of this consideration relates not only to the logic of the software routines, but also to the control requirements of external interfaces. There are two schools of thought about the planning. The rst considers that the use of ow charts is an essential requirement. The other doesn’t The advantage of using a ow chart is that it shows the questions and answers of each stage of the program in a diagrammatic form. Theory says that this chart then enables the code to be written to meet each of the requirements illustrated. The use of a ow chart certainly helps in concentrating immediate thought processes, and in recapturing concepts in the future, but it cannot display the command by command reasoning of each line of code. Only the code itself shows that, unless you also translate each line of code into lengthy textual comments, in which case there is the danger of getting bogged down with words. Additionally, there is always the possibility that some logical consideration has been omitted from the ow chart and which only comes to light once you try to run the program, requiring the chart to be redrawn as well as the software having to be rewritten. The author nds that the detailed thinking about the program structure builds up as a mental ow chart, which does not require to be set down on paper. It is acknowledged that in a commercial situation it would be mandatory for the program structure to be well documented with ow charts the program might eventually need to be changed by someone other than the original programmer. In that case, the ow chart would give a more immediate insight into the original programmer’s thought processes. owever, let us not deter you from drawing up ow charts if you prefer to do so. ou may well nd that they help you to grasp what you are doing more readily than just relying on your mental ‘visualisation’ processes. To discuss ow charts more fully is beyond the scope of this tutorial (although
Everyday Practical Electronics, August 2008
Whether or not you use ow charts, you should never attempt to write the entire program from beginning to end in one operation. That way can lead to extensive problems when you try to debug the program having found that it doesn’t do what you expected. Take each routine stage-by-stage. Get one small section of code working before you move onto the next. Then get that next small section working before you try to join it to the previous part. ‘Be methodical’ is the key command when programming. As you get further into PIC programming, you may decide that you would like to write code in conjunction with a simulation program. These help you to debug code on your PC before downloading it to the PIC. Such programs will not replace the thought processes needed when writing code, but they will let you nd many (but not all) of the errors more quickly. owever, the author nds it very easy to check program operation when the code is in the PIC and the PIC is connected to its various interfaces. ad the PIC16F628 not been an PROM device, then this would not be an acceptable technique, but it is rapidly reprogrammable and so is usable as a live test-bed. One further point, when writing a program the author nds it useful to supplement its software le name with a suf x number, increasing the number at each save of a major addition or change to the previous code written. This allows an earlier version to be recalled should the need arise, for example, PICIT01.ASM, PICIT02.ASM, PICIT03.ASM, etc.
PICs versus hardware Athough microcontrollers can be enormously bene cial, there is the likelihood that it may be regarded by the inexperienced as the ultimate answer to all electronic circuit design. This is most de nitely not the case. All that a microcontroller will do is assist in using software commands to replace a fair number of operations for which many electronic components would otherwise be needed. It cannot substitute for all electronic requirements. There are also situations in which a microcontroller can be used, but it is not necessarily desirable that it should. What you will discover as you get further into programming, is that the act of programming a PIC to replace a given number of logic chips can take far longer than if you were to design a circuit that performed the same function but only used such chips. nless you actually want to get a PIC to do something because it can, and you see it as a challenge, always ask yourself if the additional development time is worth it in order to save a chip or two.
49
Software writing generally When writing software, you will nd much frustration through the inability to immediately see the bug in a program routine. ventually, though, you will spot it and the relief and exhilaration of at last getting that part to work is enormous. In that frame of mind, you will move on to writing the next sub-routine with the utmost con dence and anticipation of not making a mistake on t is one. Would that it were so ou can, and you will, make
mistakes. But the ultimate satisfaction of a complete working design makes it all worthwhile. If you can’t take occasional bouts of desperation, isolation from friends and family, followed by periods of ecstasy and feelings of well-being towards all humanity, leave programming alone. The author, though, has become a ‘programming-addict’ and thrives on the challenges, come what may But always remember that Murphy’s Law has its most powerful in uence
when programming is involved. If the microcontroller or other computer can misunderstand what you mean by your commands, it ill. It is up to you to see the way in which each and every one of your commands will actually be interpreted. ou are the intelligent one, the computer simply obeys your instructions ext month, in the concluding part of Teach In 2008 we present a short discussion on sophisticated randomising and a practical example of it in use.
NEWSAGENTS ORDER FORM Please reserve/deliver a copy of Everyday Practical Electronics for me each month Title:
First Name:
Surname:
Address: Postcode:
Tel:
Everyday Practical Electronics is published on the second Thursday of each month and distributed S.O.R. by SEYMOUR. Make sure of your copy each month – cut out or photocopy this form, fill it in and hand it to your newsagent
Electronics Engineers - Join A Winning Team! UK, Europe and Middle East The Lektronix Group of Companies are the worlds leading provider of Industrial Automation repairs with an enviable reputation for the best in technical excellence and customer service. Due to the huge demand for our services, and our future expansion plans, we need to employ additional engineers at all our workshops to keep pace with the additional work we are receiving. We are looking for English speaking Electronic Repair Engineers, Electronic Repair Technicians and Electronic Component Level Repair Engineers in all the following locations: • Walsall, UK • Newry, Northern Ireland • Brno, Czech Republic
• Bridgend, UK • Katowice, Poland • Dubai, UAE
Do you have an interest in electronics? +DYH \RX DQ\ H[SHULHQFH LQ WKH ¿HOG RI SUDFWLFDO HOHFWURQLFV" Have you experience in Radio/Television/Home Electronics? Does your hobby/interest include electronics? Are you willing to learn new tricks – electronic engineering? Do you want work in an exciting and challenging environment? Do you have any experience with Machine Tool Systems - PLC’s - Servo Drives - Servo Motors - Monitors-VDU’s - AC Drives - DC Drives - Temperature Control - Digital Electronics – Analogue Electronics? :H RIIHU D FRPSHWLWLYH VDODU\ DQG DOO WKH RWKHU EHQH¿WV QRUPDO ZLWK D JR ahead company.
50
Please Contact: Mr Brian Stewart - Group Technical Director Lektronix International Ltd, Unit C1, Lockside, Anchor Brook Ind Park, Aldridge, West Midlands, WS9 8EQ, United Kingdom. For an application form please either: Telephone +44 (0)1922 455555, or apply online at www.lektronix.net/about/careers
Everyday Practical Electronics, August 2008
High power, high quality discrete Class D amplifier The Universal Class D (UcD) version 1.00 demonstrator board implements a 200 W true RMS (into a 4 W load) high quality audio power amplifier on a very compact printedcircuit board. The amplifier is built-up of discrete components only. The Class D concept allows efficient and cost-effective high output power audio amplifiers to be created. The Universal Class D (UcD) principle enables PWM amplifiers to perform at an excellent sonic level while making use of a relatively simple closed-loop topology.
For detail technical specifications of this discrete design, please visit: http://www.handsontec.com
http://www.handsontec.com
Teach-In 2008 Part Eleven – Randomising values with PICs, plus a Fruit Machine!
JOHN BECKER
I
N this final part of Teach-In 2008, we examine a concept that is of great benefit to many who write PIC programs for various games applications such as – randomisation. There are many occasions when games need to periodically acquire values of a random nature, using those values to determine what happens at the next stage of the game. Such values need to be arrived at in a totally unpredictable manner, and minimise the risk of occuring in a repeatable fashion. We showed in Part 3 a simple form of randomising for the Dice display, and in Part 8 for the Reaction Timing demo, yet another example was used in the Domino game last month. At the end of this part we give an example of a simple ‘One-armed Bandit’ or ‘Fruit Machine’ game that uses the more sophisicated technique described now. Using discrete electronic components there are various ways of causing circuit responses to random events. Monitoring temperature, light or noise levels and deriving usable values from those is one way in which nature can produce a random trigger event. The problem there is that that the derived value will normally only fall within a very small range. There is also the consideration that the detection circuits can become complex, which is not compatible with the basic simplicity of a circuit that is microcontroller and software based.
Fig.11.1 Circuit diagram for part 11 demos The main control section for TeachIn Y01.asm is shown in Listing 11.1. The ‘housekeeping’ initialisation routines have been omitted, but are similar to those used in the previous Teach-In 2008 demos.
Demo circuit
Simple randomising
Throughout Part 11 we shall use, in whole or in part, the circuit shown in Fig.11.1. Its breadboard layout is shown in Fig.11.2. The circuit in Fig.11.1 consists of the PIC16F628 connected to an LCD display. Switch S1 is the activating switch. Ignore the switch labelling for this demo. The PIC’s internal 4MHz oscillator is used. There are two demonstration programs, TeachInY01.asm and TeachInY02.asm. The former illustrates several methods by which random values can be generated. You select the relevant sections as instructed. The latter is the ‘Fruit Machine’, usable as a standalone program, but which you can also modify if you wish. It is discussed later.
At the simplest level in a microcontroller design, random numbers can be obtained by the mere act of pressing a switch for a length of time determined by the user, incrementing a counter during the switch press, and then taking the value that exists at the end of the switch press. Referring to Listing 11.1, switch S1 is monitored via PORTA,0. It is is normally biassed low and is repeatedly polled to see if it has been pressed: btfss PORTA,0 MAIN goto MAIN When it is pressed, there are several subroutines which can be activated to illustrate how the switch press is handled. In Listing
48
Fig.11.2. Breadboard layout for Fig.11.1 11.1, it is the routine at BYTECOUNT255 which is accessed. You can select the other options by deleting the semicolon in front of the required ‘call’ statement, and inserting a
Everyday Practical Electronics, September 2008
semicolon in front of the statement you no longer want. You then reassemble the code to a HEX file and program the PIC with it. The routine for BYTECOUNT255 is shown in Listing 11.2. When the switch is pressed, counter COUNTLSB increments at the rate at which the PIC is running (1MHz for a 4MHz oscillator) for as long as the switch is pressed. When the switch is released, the binary count value in COUNTLSB is converted to a decimal format and output to the LCD. What you then do with this value is entirely up to you. Just jotting it down on a pad is probably all you may want to do at present, just so that you can compare the results of several switch presses in a sequence. As things stand, it is the full value of the 1-byte counter, with a range of 0 to 255, which is shown, using the BIN2DEC and LCD control routines previously described. Should you wish to slow down the incrementing rate, a delay routine may be called by removing the semicolon in front of call PAUSIT.
Listing 11.1 MAIN
btfss PORTA,0 goto MAIN call CLRLINE1 call LCDMSG2
; ;
call BYTECOUNT7 call BYTECOUNT15 call BYTECOUNT255 call BYTE2COUNT call BYTECOUNT50 call BYTECOUNT7A call RANDOMISE
; ; ; ;
goto MAIN
Listing 11.2 BYTECOUNT255
incf COUNTLSB,F
;
call PAUSIT btfsc PORTA,0 goto BYTECOUNT255 call CLRLINE1 call LCD1 bsf RSLINE,4 movf COUNTLSB,W movwf REGA0 clrf REGA1 clrf REGA2 clrf REGA3 call BIN2DEC call SHOWDIGIT7 return
Value limitation In a games situation, you may not want the random value to be displayed, in which case simply omit the display commands and make use of the derived value in any way you want. If you require the random value to be limited to a maximum value below 255, this can be done in several ways. An example of limiting it to a maximum of 15 is shown in Listing 11.3. Here, the limitation is done by the insertion of the command andlw 15 (binary 00001111). Other AND values could be used instead, limiting the value to the maximum that can be held in the resulting active bits of COUNTLSB. A command of andlw 7 (binary 00000111) would result in a maximum value of 7. Of course, for a maximum value of 7, it is not necessary to use the BIN2DEC routine to convert the value for LCD display, as it is only necessary to OR the value with 48 to convert it for the LCD, as in Listing 11.4. In this instance, it is also possible to keep the value below 8 by the inclusion of the command bcf COUNTLSB,3 after incf COUNTLSB,F, as in Listing 11.5. There are situations where you may want to limit the range to a value which cannot be obtained by ANDing or clearing bits. Such would be the case if you wished to create a value predictor for Lotto, where the maximum value is 49. An example of such limitation is shown in Listing 11.6. Here the count value is constantly checked to see if it has gone beyond 49, ie to 50. If it has, the count value is reset to 0 at this point. Other values could be used instead, as appropriate to the situation. There may be occasions when you want to arrive at values within a range greater than 255. Here the counter could use two or more bytes in the counting routine, as shown in Listing 11.7, which uses two bytes, COUNTLSB and COUNTMSB. Using two bytes produces a potential maximum of
Listing 11.3 BYTECOUNT15
incf COUNTLSB,F btfsc PORTA,0 goto BYTECOUNT15 call CLRLINE1 call LCD1 bsf RSLINE,4 movf COUNTLSB,W andlw 15 movwf REGA0 clrf REGA1 lrf REGA2 clrf REGA3 call BIN2DEC call SHOWDIGIT9 return
65535. The routine could even be similarly extended to four bytes, an enormous value! All the above routines make use of the length of time that the user keeps the switch pressed. You will also have noticed that the counter is never reset at the start of the switch being pressed. This helps to randomise the value produced. Randomisation is also helped by a phenomenon discussed in a previous part – byte values themselves can take on random values at the moment that a PIC is powered up.
Automatic randomisation There are situations, though, in which random numbers may need to be generated automatically throughout a program, without the intervention of user-pressed switches.
Everyday Practical Electronics, September 2008
There are several techniques which could be used, one of which is frequently encountered in purely hardware controlled designs – using shift registers and an XOR gate. The principle is shown in Fig.11.3. Software can be used to simulate this technique. One way of doing it is shown in Listing 11.8. In Listing 11.8, the equivalent of four 8-bit shift registers are used (RANDOM1 to RANDOM4), and two XOR gates (XORGATE1 and XORGATE2). The value within the RANDOM(x) bytes is repeatedlly rotated left each time the routine at SETRANDOM is called. Selected bits of two of the RANDOM(x) bytes are monitored, and if set, then bits within the XOR gates are also set.
49
The routine is too complicated to fully describe here, but the Carry flag of STATUS is rotated into the shift register on each rotate left. The Carry flag is also affected by the status of the XOR gates. As you have been been told, any left rotation of a byte also rotates the value of the Carry flag in at the ‘right’ of the rotated byte, and the status of the final bit of that byte is rotated back into Carry. The result is that the values within the RANDOM(x) bytes change in a pseudo-random fashion each time the SETRANDOM routine is called. The value within any of the RANDOM(x) bytes can be used as the source of the required random value. That value can also be limited to a given maximum prior to it being used by the rest of the program, whatever that might be. Any of the techniques described above can be used to provide that limitation. In the TeachInY01.asm demo program, select call RANDOMISE to see the random value generated each time the switch is pressed. The routine’s details are shown in Listing 11.9.
Listing 11.4 BYTECOUNT7
Listing 11.5 BYTECOUNT7A
Seeding What may not be obvious is the fact that the value within the RANDOM(x) bytes at power-on could in fact be zero. This is a situation which can never generate a value other than zero. It is essential to ensure that this can never happen. It is possible, of course, to check the RANDOM(x) bytes for all zeros following switch-on and setting at least one of them to a non-zero value. In a simple program, however, just setting a specified value into the bytes would itself be a non-random event. What is needed is a value which itself changes each time the power is switched on. Such a value is known as a ‘seed’. One way to do this is to have a value held within the PIC’s non-volatile memory (EEPROM) which is retrieved at switch on, and then is immediately updated and stored back to the EEPROM as well as being set into RANDOM(x) bytes. In the long term, there will indeed be repetition of seed values, but this technique does help to enhance the apparent randomisation of overall value generation. Remember that in software, we can only ever use pseudo-random value generation, but extending the repetition range is highly beneficial, reducing the chances of obvious predictability. In Part 9 we illustrated how the PIC’s EEPROM could be read and written to. That technique can be used in connection with acquiring and updating the seed value. Any 8-bit value of the user’s choosing could be set into the basic ASM program, with it automaticaly being set into the PIC via the HEX file. Each time the program is run, that value would be retrieved, used and updated, say incrementing it. It would be necessary, of course, to ensure that the updated value itself was never zero. But that’s easy enough – if it is zero then increment it to 1. That concludes this section looking at obtaining random values. Let’s now look at a practical way in which randomisation is used.
50
incf COUNTLSB,F btfsc PORTA,0 goto BYTECOUNT7 call CLRLINE1 call LCD1 bsf RSLINE,4 movf COUNTLSB,W andlw 7 iorlw 48 call LCDOUT return
incf COUNTLSB,F bcf COUNTLSB,3 btfsc PORTA,0 goto BYTECOUNT7 call CLRLINE1 call LCD1 bsf RSLINE,4 movf COUNTLSB,W iorlw 48 call LCDOUT return
Listing 11.6 BYTECOUNT50
incf COUNTLSB,F movf COUNTLSB,W xorlw 50 btfsc STATUS,Z clrf COUNTLSB btfsc PORTA,0 goto BYTECOUNT50 call CLRLINE1 call LCD1 bsf RSLINE,4 movf COUNTLSB,W movwf REGA0 clrf REGA1 clrf REGA2 clrf REGA3 call BIN2DEC call SHOWDIGIT9 return
Fruity bandits ho! Just for the sheer fun of it, we now present a program which is complete in its own right – the Onearmed Bandit or Fruit Machine. You can enjoy using this on your own, or even to entertain Fig.11.3. Shift register randomisation principle your friends. The program uses the same circuit although this can be increased by the user and breadboard layout as before, but if preferred, using one of the techniques now switches S2 and S3 are brought into described earlier. use, named as S1 Spin, S2 Nudge and S3 At each press of the Spin switch, a Cheat! The program is in TEACHINY02. jackpot value is incremented, representing asm. the value that could be won when all three The program only roughly follows the wheel values are identical. The ‘wheel’ typical structure of a real gaming machine numbers cycle through the three counters of a similar nature. It effectively has three used, and are displayed on the LCD. They change so fast that the eye never sees the spinning wheels, represented by LCD actual detail. When Spin is released, the display numbers that change at the top left counter values stop changing and their of line 1. For simplicity, there is a cycle detail is shown. of four numbers for each wheel, 0 to 3,
Everyday Practical Electronics, September 2008
The software immediately checks if all three displayed numbers are the same. If they are, the value of the jackpot is added to a total and the message WINNINGS xxx appears, where xxx represents the total won since the program was switched on. If it has been won, the next press of Spin clears the jackpot display, to restart from a value of 1. If the jackpot has not been won, the numbers are checked to see if any two are the same. If they are, you can then push the Nudge switch to spin the wheel which has a value different to the other two. The spin continues for as long as the switch is pressed, again the value is displayed on the screen at a rapidly changing rate. On release of the switch, the cycling of the active counter ceases and the value now available can be seen. If the three values are now the same, you win the jackpot.
Listing 11.7 BYTE2COUNT
incfsz COUNTLSB,F goto BYTE2 incf COUNTMSB,F
BYTE2
btfsc PORTA,0 goto BYTE2COUNT call CLRLINE1 call LCD1 bsf RSLINE,4 movf COUNTLSB,W movwf REGA0 movf COUNTMSB,W movwf REGA1 clrf REGA2 clrf REGA3 call BIN2DEC call SHOWDIGIT6 return
Nudge, nudge If the jackpot has not been won the simple message NO LUCK THIS TIME! is shown and the jackpot and totals values remain unchanged. Jackpot total scoring is affected not only by the value within the jackpot, but also by the value of the winning number, 1 for 1, 2 for 2, 3 for 3, and 10 for 0. The Cheat switch allows you to always win the jackpot when the program provides the Nudge option. Pressing the switch always ensures that the ‘wrong’ number becomes the same as the other two, so ensuring a win. If you were to build this circuit on stripboard and house it in a box, you could have the Cheat switch on a lead external to the box and hidden somewhere. You could then press this switch unseen while pretending to press the Nudge switch, disguising from your friends that you are in fact cheating!
Listing 11.8 SETRANDOM
Possible changes There are changes to the program that you might like to make. You could increase the number of values that are cycled through the counters, as described above. This will make it harder for a winning combination to occur (if you are not cheating!). The scoring values at any win could also be increased quite readily. The incremental value of the jackpot can also be changed to a higher value with a spot of minor program modification. You could also allocate symbols other than the counter values themselves to be shown. For example, via a look-up table, you could allocate alphabet letters to be shown instead of the numerals. In Part 10 last month we also showed how you can create your own LCD symbols for display in place of the actual numerals. Be adventurous, have a go at changing this program to suit your own needs. What you do and how you achieve it is entirely over to you – good luck!
PIC name again That really ends this Teach-In 2008 series, but one final point is worth making. Since the series started, it has come to light that Wikipedia (http://en.wikipedia.org/ wiki/PIC_microcontroller) states that: The original PIC was built to be used with GI’s (General Instrument) new 16-
clrf XORGATE1 clrf XORGATE2 btfsc RANDOM1,2 bsf XORGATE1,0 btfsc RANDOM4,6 bsf XORGATE2,0 bcf STATUS,C movf XORGATE1,W xorwf XORGATE2,W btfsc STATUS,Z bsf STATUS,C rrf RANDOM1,F rrf RANDOM2,F rrf RANDOM3,F rrf RANDOM4,F return
Listing 11.9 RANDOMISE
call SETRANDOM call LCD1 bsf RSLINE,4 movf RANDOM1,W movwf REGA0 movf RANDOM2,W movwf REGA1 movf RANDOM3,W movwf REGA2 movf RANDOM4,W movwf REGA3 call BIN2DEC call SHOWDIGIT1 return
bit CPU, the CP1600. While generally a good CPU, the CP1600 had poor I/ O performance, and the 8-bit PIC was developed in 1975 to improve performance of the overall system by off-loading I/O tasks from the CPU. The PIC used simple microcode stored in ROM to perform its tasks, and although the term wasn’t used at the time, it shares some common features with RISC designs. In 1985, GI spun off their microelectronics division, and the new ownership cancelled almost everything – which by this time was mostly out-of-date. The PIC, however, was upgraded with EPROM to produce a programmable channel controller.
Everyday Practical Electronics, September 2008
Microchip Technology does not use PIC as an acronym; in fact the brand name is PICmicro. It is generally regarded that PIC stands for Peripheral Interface Controller, although GI’s original acronym for the initial PIC1640 and PIC1650 devices was Programmable Interface Controller. The acronym was quickly replaced with Programmable Intelligent Computer.
Further reference So, now over to you – enjoy using your PICs and the programs you write for them. And don’t forget to read PIC ‘n Mix, the regular column in EPE, which covers many aspects relating to PICs.
51
www.handsontec.com
LCD+Keyboard Shield
10-Segments LED Bar Display
Ethernet Module
Arduino Uno
MicroSD Breakout Board
WiFi Module
20x4 LCD Display Module
Stepper Motor Driver
Breakout Board & Modules
50
Integrated Circuits
Discrete Parts
PWM Motor Speed Controller
Assembled Kits
Connectors
http://www.handsontec.com