If you had graphics, you'd see our logo here.

Fast Forward Engineering


[home] [about] [ask questions] (see answers) [garage sale] [links]

The Answers

If you don't see the information you need here, please submit your question to our Embedded Systems Programming Answer Line.

Questions submitted via the Answer Line forms are answered here. When you submit a question, you'll receive an automated response within 24 hours. If you don't receive that response, please let us know in e-mail or re-submit your question.

If you do get the automated response, but the answer to your question doesn't appear here within two or three days, it simply means that we're temporarily too busy to answer questions as quickly as we'd like. Please don't re-submit your question in this case, as doing so will only make us busier. If we can't answer your question, or if we must reject it because the answer to a similar question is already posted here, we'll let you know in e-mail.

Two notes:


Note for you people who already have all the answers:

All the information on this page (except for the very few cases where we've noted otherwise) originated at Fast Forward Engineering in response to questions posed to us.

We aren't looking for submissions, so please don't send us files of subroutines, etc., that you've compiled. Aside from possible intellectual-property problems, we don't have the resources necessary to check your submissions for accuracy (it's hard enough just making sure that our own answers are correct).

If you have files that you think might be useful to microcontroller users, put them up on your own web page and let us know... We'll be happy to add a link to your site.


Microchip Technology PIC Index

  1. Why does my program work on a JW (Windowed EPROM) part, but not on an OTP part?
  2. Where can I get DIP-to-SOIC or -PLCC adapters for PICs?
  3. Why do my output pins change state when I switch them to inputs and back?
  4. How do I do an inverse sine (or any other complex trig) function with a PIC?
  5. Do I really have to disable interrupts around computed GOTOs or other direct writes to the Program Counter?
  6. [UPDATED]How can I use the DATA directive to create lookup tables for the 16Cxx?
  7. Can I use a PIC to handle MIDI data? What clock speed should I use?
  8. How can I convert an 8-bit binary number to 3 ASCII characters?
  9. Does anyone make a gang programmer for PICs?
  10. Can a program running on the 16c84 read and write the Data EEPROM when the Code-Protect fuse is enabled?
  11. Can I run a low-speed "-04" PIC at clock speeds above 4 MHz?
  12. Can I simulate an open-collector output by switching an I/O pin between "Output Low" and "Input"?
  13. What happens in the 16C71 when a stack overflow occurs?
  14. Once a stack overflow occurs, must I reset the PIC via the Watchdog Timer or MCLR to recover?
  15. On the 16Cxx, if the CCP module is set to Compare Mode and Special Trigger, will it generate an interrupt in addition to resetting Timer1?
  16. How can I get the 16Cxx's SSP mosule to do I2C Master Mode?
  17. My subroutine returns True/False in the W-register. What's the best way to test this returned value?
  18. On the 16C5x, how long can a lookup-table be?
  19. On the 16C5x, how long can a subroutine be?
  20. How can I program the 16C84's Data EEPROM with my PICSTART programmer?
  21. The PIC16s don't have a "compare" instruction. How do I compare two values?
  22. I want to compare a register to a constant. How do I do Greater-Than, Less-Than, Greater-Than-or-Equal, and Less-Than-or-Equal?
  23. I just bought a JW (windowed EPROM) PIC and it isn't stamped with a speed rating. How fast will it go?
  24. What is a PIC16C65?
  25. What is a PIC16C61?
  26. Can I run two PICs from a single clock?
  27. I want to do high-speed data transfer between two PICs. How can I synchronize their clocks?
  28. [UPDATED]Why is the "Subtract W from L" instruction called SUBLW, while the "Subtract W from F" instruction is called SUBWF?
  29. I'm loading W with 00001000 (binary), then doing an XORWF PORTA. This shouldn't affect bit 0 of PORTA, but it does. Why?
  30. In MPASM, can I define a single symbol for a Port/Bit combination?
  31. For 16Cxx parts whose General-Purpose Registers are accessible from both register pages (e.g., 16C61, 16C71, and 16C84), what's the best way to save/restore context in Interrupt Service Routines?
  32. For 16Cxx parts that have separate sets of General-Purpose Registers in each register page (e.g., all current 16Cxx parts except the 16C61, 16C71, 16C84, and 16C621/622), what's the best way to save/restore context in Interrupt Service Routines?
  33. Where I can get the Dinsmore dual hall-effect compass sensor featured in the PICSTART Design Contest Book?
  34. On the 16C74, I have the TRISE register set to all inputs and the ADCON0 register set to all zeroes (A/D Converter disabled). However, PORTE always reads 0's, even when there's a high level on the I/O pin. Why?
  35. I'm using MPASM for the 16C74. Is it possible to set configuration fuses in my source code?
  36. The PIC16C73 data sheet says that the full 13-bit address is pushed onto the stack when an interrupt occurs, and that "manipulation of the PCLATH is not required for the return instruction". How come my program's getting lost when interrupts occur?
  37. How do I tell if a PIC is "rev. A" or "rev. B"?
  38. Do the General-Purpose Registers retain their contents through a Watchdog Reset?
  39. On the 16C5x, the prescaler is shared between the RTCC and the WDT. If the prescaler is assigned to the RTCC and a CLRWDT instruction is executed, is the prescaler cleared?
  40. The 16C5x data sheet says that writes to the RTCC will clear the prescaler. Does this mean that I need to rewrite the PS0-PS2 prescaler bits in the OPTION register every time I write to the RTCC?
  41. On the 16C54, what's the fastest way to capture 8 consecutive samples on an I/O pin?
  42. What problems will I have if my PIC16C54 has a slow Vdd risetime and no R/C on the MCLR pin?
  43. Can the RTCC line on a PIC16C54 be used as input?
  44. Microchip's recommended context-saving code uses SWAPFs to save/restore the STATUS register. Can't you just use MOVFs instead?
  45. Where can I get PIC data sheets?
  46. How can lookup tables be implemented on the PIC16 series?
  47. Can a PIC be used to transmit and receive X-10 signals?
  48. The PIC data books show an unmarked series resistor in the crystal-oscillator circuit. Is this resistor necessary? If so, what value should it be?
  49. Is there a way to look at a whole port, rather than just a single pin?
  50. Does the 16C54A include a Change-on-PortB Interrupt capability?
  51. What's the difference between the 16C54 and the 16C54A?
  52. On the 16C84, can the EEADR register be changed immediately after initiating a write to the Data EEPROM?
  53. I just downloaded the new version of MPASM, and suddenly my code produces hundreds of "Using default destination of 1 (file)" messages. Why?
  54. On the 16C74, I've set RA0 and RA1 as analog inputs and RA2-RA5 as digital outputs. When I use BCF or BSF to alter RA5, RA3 goes low. Why?
  55. The 16C84 data book shows a minimum Watchdog Timer period of 7 milliseconds and a maximum EEPROM Write time of 10 ms. How do I ensure that the Watchdog Timer won't expire during EEPROM writes?
  56. The 16C5x has only a two-level stack. Microchip has an appnote which describes a way to simulate a larger stack in software, but it uses way too much RAM and time. Is there some other way?
  57. When I erase a PIC, it seems that the configuration fuses take much longer to erase than the rest of the EPROM. Is something wrong with my chip or eraser?
  58. On the 16Cxx parts with built-in PWM generators, how do I use 10-bit resolution instead of eight-bit?
  59. How can I perform a checksum on the PIC16 code space?
  60. What C compiler would you recommend for PIC16/17 development?
  61. Is there a Windows-based simulator for the 16C5x?
  62. How do I use the FSR and INDF registers to indirectly access the PIC's registers?
  63. Can you explain the representation used in Microchip's appnotes for floating-point numbers?
  64. How do I do an 8-bit divide on a PIC16C5x?
  65. Using a 16C5x (with no A/D converter), how can I measure the position of a pot?
  66. How can I generate NTSC video sync, optionally synched to an external source, with a PIC16C71 running at 20 MHz?
  67. [UPDATED]I need to generate precise delays using a PIC. How do I do this?
  68. How do I interface the PIC16C64/74's Parallel Slave Port to an ISA-Bus PC?
  69. Are there any undocumented bugs in Microchip's MPSIM simulator?
  70. I'm interfacing my PIC to AC power lines and need to protect it from power surges. What external circuitry should I use?
  71. [UPDATED]I'm using an Apple Macintosh. What PIC development tools do you recommend?
  72. I'm using an IBM-compatible PC running Windows. What PIC development tools do you recommend?
  73. I've heard of third-party PIC programmers that cost as little as $15. Are they any good?
  74. I'm using a Microchip PRO MATE programmer. Occasionally, its "blank-check" feature tells me that a chip is blank, but the "verify" feature tells me that it's programmed. What's going on here?
  75. [UPDATED]Is it possible to generate a sequence of 8-bit pseudo-random numbers on a PIC?
  76. How do I generate a CRC (Cyclic Redundancy Check) using a PIC?
  77. Can I write a routine that will generate various time delays which can be called from multiple points throughout my program?
  78. I'm writing macros in MPASM. How do I define labels within the macro so that they're given unique names each time the macro is invoked?
  79. What is a PIC16C52? Is it pin-compatible with the 16C54?
  80. The 16C73 and 16C74 can output in Pulse Width Modulation (PWM). How can I receive and decode this using another PIC?
  81. Is there an automated way to convert code written for the PIC16C71 to the Motorola 68HC11?
  82. How can I disassemble the code in a PIC?
  83. What is the maximum current limit through the protection diodes on the PIC I/O ports?
  84. What's the difference, if any, between Byte Craft's MPC compiler and Microchip's MPLAB-C?
  85. I'm trying to use pin RA4 on a PIC16Cxx and it doesn't seem to work properly. What's wrong?
  86. I've never used interrupts before. I see that when TMR0 overflows, the T0IF bit is automatically set. If I have to poll that bit, how is this any better than simply polling TMR0 to see when it overflows?
  87. Is it possible to store data in an external memory (preferably SRAM) using a PIC16C84?
  88. The PIC16C6X datasheet says that under certain conditions, Change-On-PortB interrupts may be missed. Is this true?
  89. Can you recommend a good book for a beginning PIC programmer?
  90. I want to write code for the new PIC12C50x. What version of MPASM do I need?
  91. How can I generate DTMF (Touch-Tone) tones using a PIC?
  92. I want to alter the contrast of a standard Hitachi-controller LCD display. Can I use PWM?
  93. I'm running my PIC from two AA cells. I'd like to protect it in the event that the batteries are inserted backward, but I can't afford the voltage drop from a series diode. Any ideas?
  94. I saw the 8-bit divide routine in Question #64, but I can't figure out how to extend it to divide one 16-bit number by another. How do you do a 16-bit divide?

Motorola 6805 Index

  1. In the 68705P3/R3/U3, how is the "contents dump" feature invoked?
  2. Where can I find sample code for the 68HC05?
  3. I'm learning Microchip PIC assembly language. Once I'm comfortable with it, will it be hard to learn Motorola 6805 assembly?

Other Processors/Miscellaneous Index

  1. I'm writing a real-time clock/calendar program. How do leap-years work?
  2. Where can I get a solid-state air-pressure sensor?
  3. What's the phone number for DIGI-KEY?
  4. Do you have any advice on laying out PC boards for high-noise environments?
  5. What are Gray codes and how do I generate them?
  6. I'm running Windows. What text editor do you recommend?
  7. Where can I get the Brief editor?
  8. [Name deleted] said that he could write what I think is a 4-week assembly-language program in only a couple of days. Can this possibly be true?
  9. I'm looking for a source of RF transmitters/receivers for a remote-control project. Any ideas?
  10. I need to decode "RC5" commands from an infrared remote control. Where can I find information on this protocol?
  11. Do you have the name or number of a Ricoh distributor?
  12. What are the relative merits of C versus Assembly-Language for microcontroller programming?
  13. I've heard that X-10 devices don't always work well. Is this true?
  14. I need a high-accuracy 4 MHz crystal. Where can I get one?
  15. I need to decode a Manchester-encoded data stream from a TV-type remote control. Want to write the program for me?
  16. Have you ever considered authoring an article for [a popular electronics-engineering magazine]?
  17. I have a product based on the Hitachi 6303, which is being discontinued. Does anyone make a compatible processor? Can you point me to someone who could duplicate the 6303 in an ASIC?
  18. I need a microcontroller with built-in OSD (On-Screen Display) and I2C-bus support. Any suggestions?
  19. What is a SAW transmitter, and how does it give you increased range over cheap tuned-L/C transmitters?
  20. Where can I find a good description of CRC (Cyclic Redundancy Check) algorithms and theory?
  21. What are Hamming codes, what do they do, and how can I use them?

Microchip Technology PIC

Why does my program work on a JW (Windowed EPROM) part, but not on an OTP part?

Are you initializing all the file registers and the OPTION register?

With the window uncovered, a JW part can clear all its File Registers just by being exposed to light. If you're not explicitly initializing RAM, this is kinda handy. If you cover the window, though, the JW part behaves just like the OTP; the File Registers all come up in unknown states and the code doesn't work. 

Where can I get DIP-to-SOIC or -PLCC adapters for PICs?

Emulation Technology (408 982-0660) is an excellent source for surface-mount sockets, test clips, package adapters (DIP-to-SOIC, PGA-to-PQFP, etc.), logic analyzer/oscilloscope adapters, etc.

EDI Corporation also has a pretty complete line, and their prices are often considerably better than Emulation Technology's. 

Why do my output pins change state when I switch them to inputs and back?

1. Let's say port B0 is connected to +5V thru a resistor. You have port B0 configured as an output, and you're driving it low (PORTB = xxxxxxx0, TRISB = xxxxxxx0).

2. Now you change port B0 to an input (TRISB = xxxxxxx1), and read PORTB (with a MOVF PORTB,W or something). Since B0 is pulled up, you'll read a "1" on B0 (PORTB = xxxxxxx1).

Following so far? Good...

3. Now you make port B0 an output again (TRISB = xxxxxxx0), and, since PORTB = xxxxxxx1, the B0 pin will be driven HIGH.

To keep this from happening, you should always load PORTB with the values you expect on the output pins JUST BEFORE you make them outputs. In the example above, a BCF PORTB,0 just before step 3 would have ensured that the pin would drive low after changing the TRISB register.

Of course, you may just be neglecting to set the register-page select bits properly before you write to TRISB, and you might actually be writing to PORTB inadvertently. Since TRISB is on the upper page of registers, you must be sure that RP0 is set before you write to TRISB. 

How do I do an inverse sine (or any other complex trig) function with a PIC?

Use a lookup table; for the inverse sine, you only need to store 1/4 of a circle (1/8 if you have compute-time to spare), so it won't take much storage space. 

Do I really have to disable interrupts around computed GOTOs or other direct writes to the Program Counter?

No. The information in Microchip's AN-556 appnote is incorrect. 

How can I use the DATA directive to create lookup tables for the 16Cxx?

You can't.

Well, ok... You can, but you don't want to. Use the DT directive instead.

    DT "Test",0
will assemble to:
     RETLW "T"
     RETLW "e"
     RETLW "s"
     RETLW "t"
     RETLW 0

Can I use a PIC to handle MIDI data? What clock speed should I use?

Sure. PICs run at up to 5 MIPS (with a 20MHz crystal), and the MIDI data stream is at 31.25 Kbits/sec. If you need to send precisely-timed MIDI data, you'll need to be running your PIC at a multiple of 125KHz. Fortunately, the 31.25K MIDI data rate was chosen precisely because there are so many off-the-shelf crystals/resonators that run at those multiples.

A 4 MHz clock speed will give you 32 machine cycles per bit, which should be plenty of time to do what you want. If you need more time, you can run faster. 

How can I convert an 8-bit binary number to 3 ASCII characters?

     LIST    R=DEC

     ASCIIO  EQU     ....    ;A FILE REGISTER.
     ASCIIT  EQU     ....    ;ANOTHER FILE REGISTER.
     ASCIIH  EQU     ....    ;ANOTHER FILE REGISTER.

; ENTER WITH ORIGINAL 8-BIT VALUE IN "ASCIIO".  EXITS WITH ASCII
; REPRESENTATION OF ONES' DIGIT IN "ASCIIO", TENS' DIGIT IN "ASCIIT",
; AND HUNDREDS' DIGIT IN "ASCIIH".

CONVRT  MOVLW   '0'
        MOVWF   ASCIIH
        MOVWF   ASCIIT

DO100S  MOVLW   100
        SUBWF   ASCIIO,W
        BNC     DO10S

        MOVWF   ASCIIO
        INCF    ASCIIH
        GOTO    DO100S

DO10S   MOVLW   10
        SUBWF   ASCIIO,W
        BNC     ADJUST

        MOVWF   ASCIIO
        INCF    ASCIIT
        GOTO    DO10S

ADJUST  MOVLW   '0'
        ADDWF   ASCIIO

Does anyone make a gang programmer for PICs?

Yeah... Try these people:
          Manufacturer          Model                   Telephone
          ------------          -----                   ---------
       Advanced Transdata      PGM16X8                 214 980-2960
       Elan Digital Systems    5-940                   800 541-ELAN
       ICE Technology          Speedmaster 8000        716 475-0495
       Logical Devices         GANGPRO-S               305 428-6868
       MQP Electronics         MQP System 2000         44 666-8252146
       Paragon Programming     PPC-9201                513 244-1116
       Stag Programmers        Solar                   408 988-1118
       Unitec Electric         Pim/10                  81 255 74-4124
If you're in Europe, try:
       Elan Digital Systems            44 489-579799 (England)
       ICE Technology (c/o Magnadata)  49 6082 1615 +742 (Germany)
       ICE Technology (c/o Infratech)  49 40 81 75 78 (Germany)
       MQP Electronics                 49 89/4602071 (Germany)
       Stag Programmers                44 707 332148 (England)

Can a program running on the 16c84 read and write the Data EEPROM when the Code-Protect fuse is enabled?

Yes. The code-protect fuse, as its name implies, only protects the code space; after it's blown, the data space is still available to your program. 

Can I run a low-speed "-04" PIC at clock speeds above 4 MHz?

Probably. The only difference between the -04s and the -10s and -20s is the testing that the chips undergo at the factory. If your -04 part doesn't fail immeditely when run at a higher speed, it probably never will.

On the other hand, I wouldn't recommend over-revving PICs in any real production units of your product; the high-speed parts don't cost all that much more. 

Can I simulate an open-collector output by switching an I/O pin between "Output Low" and "Input"?

Yes, but you have to be a little careful: Make sure that you always write a "0" to the appropriate bit of your Port register immediately before you make the pin an output. 

What happens in the 16C71 when a stack overflow occurs?

All that happens is that the least-recent return address is lost. As RETLW, RETURN, and RETFIE instructions are subsequently executed, addresses are popped off the top of the stack and the address at the bottom of the stack is copied to the address above it. This means that when it comes time for that last RETURN, the address at the top of the stack will be wrong.

Here's a visual aid showing the contents of the stack at 6 different times, labeled a through f:

       a.      b.      c.      d.      e.      f.

       0C0     0D0     0C0     070     060     060
       0B0     0C0     0B0     060     060     060
       0A0     0B0     0A0     060     060     060
       090     0A0     090     060     060     060
       080     090     080     060     060     060
       070     080     070     060     060     060
       060     070     060     060     060     060
       050     060     060     060     060     060
At a., the stack is full. After 8 RETURNs, we'll be back at our starting point, 050. At b., we've done one more CALL, pushing the lowest address off the stack. At c., we've done a RETURN... see what happens at the bottom of the stack?

The diagram at d. shows what's happened after five more RETURNS. Everything's still going smoothly at e., one RETURN later. After returning to address 060, though, a further RETURN will not send us back to our original starting point (address 050). Instead, we'll just get stuck in a loop between 060 and the first RETURN after 060. 

Once a stack overflow occurs, must I reset the PIC via the Watchdog Timer or MCLR to recover?

No. Simply jumping to any convenient entry point at the topmost level of your program will put the stack and the PC back in sync. For most programs, this entry point will have to be the start of the program (the address pointed to by the reset vector). 

On the 16Cxx, if the CCP module is set to Compare Mode and Special Trigger, will it generate an interrupt in addition to resetting Timer1?

No. The "Special Trigger " and "Software Interrupt" modes are mutually exclusive. 

How can I get the 16Cxx's SSP mosule to do I2C Master Mode?

You can't; the 16Cxx hardware supports Slave Mode only. No one knows why. 

My subroutine returns True/False in the W-register. What's the best way to test this returned value?

I'd do something like the following:
            CALL    TEST                    ;Subroutine returns with W=0 for FALSE, W=1 for TRUE.

            ADDWF   PCL                     ;For the 16C5x, this should be "ADDWF PC".
            GOTO    FALSE

    TRUE    ....
Of course, care must be taken with page-boundary crossings. If you're using the 16Cxx, you'll need to make sure that PCLATH is pointing at the current page before you do the ADDWF. On the 16C5x, this code-fragment will only work if TRUE is on the first half of a page, and (for the 16C56/57/58) you'll need to ensure that the code-page select bits are pointing at the current page before you do the ADDWF. 

On the 16C5x, how long can a lookup-table be?

255 bytes (or 256 if you're using a 16C56, '57, or '58 and are willing to do some tricky programming), since the lookup-table-subroutine entry-point and all table entries must reside in the lower half (256 bytes) of a page. 

On the 16C5x, how long can a subroutine be?

As long as you like. The only restriction is that the subroutine's entry- point (the address you CALL) must reside in the lower half (256 bytes) of a page. The subroutine itself can extend into the upper half of the page. In fact, you can just put a GOTO at the start of your subroutine and jump anywhere you like. 

How can I program the 16C84's Data EEPROM with my PICSTART programmer?

You can't (yet). Microchip doesn't include Data-EEPROM programming in the current PICSTART software; they suggest that you buy a PROMATE programmer if you need this feature.

If you're willing to go to a bit of trouble, you can do it in a two-step process:

Write a short 16C84 program that just programs your EEPROM to the desired values. Burn it into a 16C84, run the program, then burn the 16C84 with your real code. 

The PIC16s don't have a "compare" instruction. How do I compare two values?

Depends on what comparison you're trying to make. If it's a greater-than/less-than/equal kind of thing, and you're comparing the contents of two registers, you're basically limited to doing a subtraction and checking the flags in the Status register. For other types of comparisons, XORs (or other Boolean operations) can be used.

If you really get lucky and find yourself trying to determine something simple, like whether the contents of a register are greater than 127, you can, of course, just do a single bit-test. 

I want to compare a register to a constant. How do I do Greater-Than, Less-Than, Greater-Than- or-Equal, and Less-Than-or-Equal?

       MOVLW   constant        ;If register = constant, jump.
       SUBWF   register,W
       BZ      R_EQUALS_C

       MOVLW   constant        ;If register >= constant, jump.
       SUBWF   register,W
       BC      R_GT_EQ_C

       MOVLW   constant        ;If register < constant, jump.
       SUBWF   register,W
       BNC     R_LT_C

       MOVLW   constant        ;If register > constant, jump.
       SUBWF   register,W
       SKPZ
       SKPC
       GOTO    $+2
       GOTO    R_GT_C

       MOVLW   constant        ;If register <= constant, jump.
       SUBWF   register,W
       BZ      R_LT_EQ_C
       BNC     R_LT_EQ_C
Note that the ">" and "<=" tests use more space than the others. Rather than testing for "greater than x", therefore, you may wish to test for "greater than or equal to x+1". Likewise, instead of testing for "less than or equal to x", you may wish to test for "less than x+1". 

I just bought a JW (windowed EPROM) PIC and it isn't stamped with a speed rating. How fast will it go?

Only the OTP parts have speed ratings; the windowed parts will work over the entire range (up to 20 MHz for most PICs). 

What is a PIC16C65?

It's a 16C74 whose internal A/D converter has been disabled. 

What is a PIC16C61?

It's a 16C71 whose internal A/D converter has been disabled. 

Can I run two PICs from a single clock?

Yeah... There are two ways:

If you have an external clock (with an oscillator and everything... not just a crystal or ceramic resonator), you can obviously run its signal to the CLKIN (OSC1) pin of each PIC.

If you're using the PIC's built-in oscillator with an external crystal or ceramic resonator, you can simply tie one PIC's CLKOUT (OSC2) pin to the other's CLKIN, then put the crystal/resonator between the two remaining OSC pins. Some experimentation with capacitor values may be necessary. 

I want to do high-speed data transfer between two PICs. How can I synchronize their clocks?

Since you also asked about running two PICs from the same clock, I'm sure you realize that by doing so, most of the expected handshaking could be eliminated.

Unfortunately, the PICs' instruction clocks run at 1/4 the external clock frequency. While it's pretty easy to sync the PICs to within 1 instruction cycle, there's no way to guarantee that each PIC's divided-down instruction clock is exactly in sync with the other's. Because the oscillator startup timer is dependent on an inaccurate internal R/C, the PICs will probably be out of sync by 1 or 2 oscillator periods in either direction.

This means is that you'll still have to allow some time between placing data on the bus and taking it off, even if your software is clever enough to get the PICs in sync to within 1 instruction cycle. 

Why is the "Subtract W from L" instruction called SUBLW, while the "Subtract W from F" instruction is called SUBWF?

I don't know. When I find out who made this decision, I will kill him.

Actually, Martin J. Maney (who's apparently a little more level-headed than I) recently explained the inconsistency thusly:

The first PICs (all the way back to General Instruments' NMOS 1650) didn't include "subtract" instructions. They did have "literal" instructions (ADDLW, XORLW, etc.), but none of those instructions was order-dependent. The only instruction that was order-dependent was MOVLW, so GI/Microchip set the order of all the literal instructions to match it.

By the time that the "Subtract W from L" instruction was added to the newer PICs' instruction sets, it was too late... All the other literal instructions already used the "....LW" ordering, so Microchip applied it to the SUBLW instruction, too.

Personally, this explanation leaves me a little unsatisfied -- foolish consistency is, as they say, the hobgoblin of little minds -- but I guess it'll have to do. At least it takes the edge off my homicidal urge. 

I'm loading W with 00001000 (binary), then doing an XORWF PORTA. This shouldn't affect bit 0 of PORTA, but it does. Why?

The XORWF instruction reads the values of the port pins (which may be different from the values in the port output latch), does the exclusive-OR, then writes the result to the output latch. If your RA0 pin is at a voltage higher than 2 Volts or so when the XORWF is executed (even if you've previously written a "0" to PORTA,0), the XORWF will read that pin value as a "1", then write the "1" back to the output latch. 

In MPASM, can I define a single symbol for a Port/Bit combination?

Sure... Use a #DEFINE, like this:
    #DEFINE LED     PORTA,0                 ;The LED is on RA0.

    ....

            BSF     LED                     ;Turn the LED on.

For 16Cxx parts whose General-Purpose Registers are accessible from both register pages (e.g., 16C61, 16C71, and 16C84), what's the best way to save/restore context in Interrupt Service Routines?

    INTW    EQU     [any page-0 register]
    INTS    EQU     [any page-0 register]

            ....

    ; INTERRUPT SERVICE ROUTINE:

    PUSH    MOVWF   INTW                    ;SAVE THE W-REGISTER.

            SWAPF   STATUS,W                ;SAVE THE STATUS REGISTER.
            MOVWF   INTS                    ;

            BCF     STATUS,RP0              ;MAKE SURE WE'RE ON REGISTER PAGE 0 [optional].

            ....

    POP     SWAPF   INTS,W                  ;RESTORE THE STATUS REGISTER.
            MOVWF   STATUS                  ;

            SWAPF   INTW                    ;RESTORE THE W-REGISTER.
            SWAPF   INTW,W                  ;

            RETFIE                          ;RETURN AND RE-ENABLE INTERRUPTS.

For 16Cxx parts that have separate sets of General-Purpose Registers in each register page (e.g., all current 16Cxx parts except the 16C61, 16C71, 16C84, and 16C621/622), what's the best way to save/restore context in Interrupt Service Routines?

    INTW    EQU     [any page-0 register]
    INTS    EQU     [any page-0 register]
    INTW1   EQU     INTW + 080H

            ....

    ; INTERRUPT SERVICE ROUTINE:

    PUSH    MOVWF   INTW
            MOVF    STATUS,W
            BCF     STATUS,RP0
            MOVWF   INTS
            ; save PCLATH and FSR here.

            ....

    POP     ; restore PCLATH and FSR here.
            MOVF    INTS,W
            MOVWF   STATUS
            SWAPF   INTW
            SWAPF   INTW,W
            RETFIE

Where can I get the Dinsmore dual hall-effect compass sensor featured in the PICSTART Design Contest Book?

Dinsmore Instrument Co.

1814 Remell St.
PO Box 345
Flint, MI 48501
810 744-1330
810 744-1790 (Fax)

On the 16C74, I have the TRISE register set to all inputs and the ADCON0 register set to all zeroes (A/D Converter disabled). However, PORTE always reads 0's, even when there's a high level on the I/O pin. Why?

If you're not using the A/D, you have to set ADCON1 to xxxxx11x binary to select Digital Inputs for the PORTA/PORTE pins; setting ADCON0 to 00 isn't enough.

Note that the ADCON1 register defaults to 00 on power-up.

This is also an issue for the 16C71, in which ADCON1 must be set to xxxxxx11 binary. 

I'm using MPASM for the 16C74. Is it possible to set configuration fuses in my source code?

Sure, as long as you're using a version of MPASM later than about 1.20. Here's an example for the 16C74. In your own code, you should probably use the fuse-definition equates that are included in the "16CXX.INC" and "17CXX.INC" files distributed with MPASM, since they're guaranteed to have the correct values for current parts.
    ; NOTE:  THIS IS FOR THE CURRENT VERSION OF THE 16C74 ONLY!

    CP_ALL  EQU     03F8FH          ;NOTE:  These equates are for the
    CP_75   EQU     03F9FH          ;       current version of the
    CP_50   EQU     03FAFH          ;       PIC16C74 ONLY!
    CP_OFF  EQU     03FBFH          ;
    PWRT    EQU     03FBFH          ;       They are NOT for the 16C74A,
    NO_PWRT EQU     03FB7H          ;       nor are they guaranteed to
    WDT     EQU     03FBFH          ;       work on any other devices.
    NO_WDT  EQU     03FBBH          ;
    LP_OSC  EQU     03FBCH          ;
    XT_OSC  EQU     03FBDH          ;
    HS_OSC  EQU     03FBEH          ;
    RC_OSC  EQU     03FBFH          ;

            __FUSES CP_ALL & PWRT & NO_WDT & XT_OSC   ;Enable code
                                                      ;protection and
                                                      ;power-up
                                                      ;timer, disable
                                                      ;the watchdog
                                                      ;timer, and
                                                      ;select XT
                                                      ;oscillator.
Note that the __FUSES directive is preceded by two underscores, not one. 

The PIC16C73 data sheet says that the full 13-bit address is pushed onto the stack when an interrupt occurs, and that "manipulation of the PCLATH is not required for the return instruction". How come my program's getting lost when interrupts occur?

The full 13-bit return address IS stored on the stack, but PCLATH isn't. If your interrupt-service routine modifies PCLATH, you must restore it before the RETFIE.

One more thing to note: If you have a GOTO at the interrupt vector (address 0004), remember that it behaves just like any other GOTO; if PCLATH is set when an interrupt occurs, the PIC will jump to an address on page 1. To avoid problems, don't put a GOTO at the interrupt vector. Instead, you can either put your whole interrupt routine at 004 or put just the register-saving code there, followed by a GOTO to the rest of your ISR.

The best way to save registers on the 16C73 is something like this:

       INTW    EQU     any page-0 register
       INTW1   EQU     INTW + 080H
       INTS    EQU     any page-0 register
       INTP    EQU     any page-0 register
       INTF    EQU     any page-0 register

               ORG     0004h

       INTVEC:

               MOVWF   INTW
               MOVF    STATUS,W
               BCF     STATUS,RP0
               MOVWF   INTS
               MOVF    PCLATH,W
               MOVWF   INTP
               MOVF    FSR,W
               MOVWF   INTF
               ;at this point, if you like, you can modify PCLATH and
               ;jump to the rest of the ISR on another page.
Then, to restore the registers at the end of your ISR, do this:
               MOVF    INTF,W
               MOVWF   FSR
               MOVF    INTP,W
               MOVWF   PCLATH
               MOVF    INTS,W
               MOVWF   STATUS
               SWAPF   INTW
               SWAPF   INTW,W
               RETFIE

How do I tell if a PIC is "rev. A" or "rev. B"?

Silkscreened on the face of the chip is a four-digit number, like 9420, followed by a 3-letter group like "CAB" or "SAT". The silicon revision-level is the middle letter of the three-letter group; for both of these examples, the chip is a "rev. A".

The 4-digit number, by the way, is a date-code. "9420" means that the chip was packaged in the 20th week of 1994. 

Do the General-Purpose Registers retain their contents through a Watchdog Reset?

Yes. 

On the 16C5x, the prescaler is shared between the RTCC and the WDT. If the prescaler is assigned to the RTCC and a CLRWDT instruction is executed, is the prescaler cleared?

The prescaler isn't shared, exactly; it's switched. If it's assigned to the RTCC, CLRWDT commands will not affect it. 

The 16C5x data sheet says that writes to the RTCC will clear the prescaler. Does this mean that I need to rewrite the PS0-PS2 prescaler bits in the OPTION register every time I write to the RTCC?

No. The prescaler is an internal counter, inaccessible by your code (i.e., you can't read it or write an arbitrary value to it; your only control over its value is the "clear prescaler to 0" that occurs when you write to the RTCC).

The prescaler is not contained in the OPTION register. The OPTION register's PS0-PS2 bits only set the divide-by ratio, or range, of the prescaler, and they are changed only by RESET and explicit writes to the OPTION register. They are not affected by writes to the RTCC. 

On the 16C54, What's the fastest way to capture 8 consecutive samples on an I/O pin?

If you can afford the I/O, this is the fastest possible way.

Put the signal on Port B0, leaving B1-B7 unused. Then:

       SETUP   MOVLW   00000001B       ;MAKE B0 AN INPUT, B1-B7 OUTPUTS.
               TRIS    PORTB           ;

       SAMPLE  RLF     PORTB           ;SHIFT 7 CONSECUTIVE SAMPLES OF
               RLF     PORTB           ;B0 INTO B7-B1.
               RLF     PORTB           ;
               RLF     PORTB           ;
               RLF     PORTB           ;
               RLF     PORTB           ;
               RLF     PORTB           ;

               MOVF    PORTB,W         ;W-REG CONTAINS LAST 8 SAMPLES
                                       ;(MSB = EARLIEST, LSB = LATEST).

What problems will I have if my PIC16C54 has a slow Vdd risetime and no R/C on the MCLR pin?

Extremely slow Vdd rise times generally cause the PIC to latch up, or "hang". This latch-up is caused by the PIC's logic circuits beginning to function before the PIC's memory can.

To recover, MCLR must be pulsed or Vdd must be lowered (below 0.7V), then raised (more quickly than 0.05V/ms). 

Can the RTCC line on a PIC16C54 be used as input?

The level on the RTCC pin can't be read directly, but you can sense low-to-high or high-to-low transitions by setting the OPTION register for "RTCC Signal Source = Transition on RTCC Pin", "Prescaler Assigned to WDT", and either "Increment on Lo-to-Hi Transition" or "Increment on Hi-to-Lo Transition".

Once the OPTION register is set, every transition on the RTCC pin will increment the contents of the RTCC register. By monitoring that register, you can easily see when transitions occur. 

Microchip's recommended context-saving code uses a SWAPF to save the STATUS register. Can't I just use a MOVF instead?

Sure. Microchip's suggested 16C71 code looks like this:
    INTW    EQU     [any page-0 register]
    INTS    EQU     [any page-0 register]

            ....

    ; INTERRUPT SERVICE ROUTINE:

    PUSH    MOVWF   INTW                    ;SAVE THE W-REGISTER.

            SWAPF   STATUS,W                ;SAVE THE STATUS REGISTER.
            MOVWF   INTS                    ;

            BCF     STATUS,RP0              ;MAKE SURE WE'RE ON REGISTER PAGE 0 [optional].

            ....

    POP     SWAPF   INTS,W                  ;RESTORE THE STATUS REGISTER.
            MOVWF   STATUS                  ;

            SWAPF   INTW                    ;RESTORE THE W-REGISTER.
            SWAPF   INTW,W                  ;

            RETFIE                          ;RETURN AND RE-ENABLE INTERRUPTS.
Changing the SWAPF STATUS,W to MOVF STATUS,W will work just fine, since the Z-Flag (which can be changed by that MOVF) won't change until after the contents of STATUS are copied to the W-Register.

Of course, if you use MOVF STATUS,W in your "save" code, you must use a corresponding MOVF INTS,W in your "restore" code. 

Where can I get PIC data sheets?

PIC data sheets are available from your local Microchip representative, from the Microchip BBS, and from Microchip's World-Wide Web site. As a last resort, they're also available from many catalog distributors like Digi-Key.

The best source, by far, is your local Microchip sales rep. Contact information is on Microchip's Web page.

If you don't mind reading data books on your PC screen, you can download the data sheets, in Adobe Acrobat format, from either Microchip's BBS or from their Web site (an Acrobat Reader is available from those sites, too). The BBS is accessible through Compuserve's network (although you don't have to be a Compuserve member to use it), so it's a local call from nearly everywhere in the U.S. The Web site is at http://www.ultranet.com/microchip

How can lookup tables be implemented on the PIC16 series?

Since the PIC16s can't directly access program memory, traditional methods won't work. Instead, create a series of RETLWs, using the elements of the table as the operands of the RETLWs, then access them by CALLing a subroutine which directly modifies the Program Counter to jump to the appropriate RETLW.

Here's a 16C5x example:

    ;
    ;RETURN THE X'TH PRIME NUMBER, WHERE X IS IN THE RANGE [1-10].
    ;ENTER WITH X IN THE W-REGISTER, EXITS WITH THE X'TH PRIME NUMBER
    ;IN THE W-REGISTER.
    ;

    LOOKUP  ADDWF   PC              ;JUMP TO THE APPROPRIATE RETLW.

            NOP                     ;"ZERO'TH" PRIME NUMBER WOULD GO HERE.

            RETLW   2               ; 1ST PRIME NUMBER IS  2.
            RETLW   3               ; 2ND PRIME NUMBER IS  3.
            RETLW   5               ; 3RD PRIME NUMBER IS  5.
            RETLW   7               ; 4TH PRIME NUMBER IS  7.
            RETLW   11              ; 5TH PRIME NUMBER IS 11.
            RETLW   13              ; 6TH PRIME NUMBER IS 13.
            RETLW   17              ; 7TH PRIME NUMBER IS 17.
            RETLW   19              ; 8TH PRIME NUMBER IS 19.
            RETLW   23              ; 9TH PRIME NUMBER IS 23.
            RETLW   29              ;10TH PRIME NUMBER IS 29.

    ....

    MAIN    MOVLW   7               ;LOOKUP THE 7TH PRIME NUMBER.
            CALL    LOOKUP          ;

            MOVWF   RESULT          ;STORE IT IN "RESULT".
There are a couple of things to note here. First, the range of inputs to the LOOKUP subroutine must be tightly constrained. In our example, W must be in the range [1-10]; calling LOOKUP with W > 10 will cause disastrous results, as the Program Counter will end up pointing God-knows-where in your program. Second, you need to remember that if W = 0 on entry to the subroutine, the ADDWF will point the Program Counter to the instruction after the ADDWF, since the PIC increments its Program Counter before executing the instruction. For this reason, our example (which only deals with inputs > 0) puts a NOP right after the ADDWF.

Ok... Some more things:

On the 16C5x parts, the ADDWF and each of the RETLWs must be located in the first half of the code page in which they're located. That is, the entire subroutine must fit in the [000-0FF], [200-2FF], [400-4FF], or [600-6FF] areas.

For the 16Cxx parts, the subroutine can be anywhere in memory, but the PCLATH register should be loaded with the hi-byte of the table-elements' addresses before calling LOOKUP. That is, the MAIN routine should look like this:

    MAIN    MOVLW   HIGH (LOOKUP+1) ;MAKE SURE THAT THE "ADDWF" IN "LOOKUP"
            MOVWF   PCLATH          ;JUMPS TO THE CORRECT PAGE.

            MOVLW   7               ;LOOKUP THE 7TH PRIME NUMBER.
            CALL    LOOKUP          ;

            MOVWF   RESULT          ;STORE IT IN "RESULT".

            MOVLW   HIGH ($+2)      ;RESTORE THE PCLATH REGISTER.
            MOVWF   PCLATH          ;
This assumes that the whole lookup-table subroutine fits in one 256-byte page of memory. If the table crosses page-boundaries, the PCLATH must be pre-conditioned to point at the appropriate page for the element being accessed. Since it's usually very easy to keep tables in one page, I won't show the necessary code here; if you need it, it's in Microchip's Application Note #AN556. 

Can a PIC be used to transmit and receive X-10 signals?

Yes. The last time I checked, however, the X-10 protocol was still patent-protected. The patent used to be owned by a company called BSR, but a new company called simply X-10, Inc., now seems to control it. For information on the "X-10 Powerhouse" interface, or for patent-license information, you can contact them at:

X-10, Inc.
185-A Legrand Avenue
Northvale, NJ 07647
Tel: 201 784-9700

The PIC data books show an unmarked series resistor in the crystal-oscillator circuit. Is this resistor necessary? If so, what value should it be?

The series resistor is usually necessary only when you're using the PIC in High-Speed (HS) mode. It's only there to prevent over-driving of the crystal; I've used values around 470 ohms. 

Is there a way to look at a whole port, rather than just a single pin?

Sure... Since the ports are treated just like other file registers, you can perform any of the file-oriented instructions on them. For example:
            MOVF    PORTB,W         ;READ ALL 8 BITS OF PORTB INTO THE W-REGISTER.

            or

            MOVLW   00001111B       ;PULL RB4-RB7 OUTPUTS LOW.
            ANDWF   PORTB           ;

            or

            MOVF    PORTB,W         ;GRAB THE STATE OF ALL 8 PORTB PINS.
            MOVWF   LAST            ;STORE IT.

    WAIT_FOR_CHANGE:
            MOVF    LAST,W          ;COMPARE THE STORED STATE TO THE CURRENT STATE
            XORWF   PORTB,W         ;(WITHOUT AFFECTING EITHER "PORTB" OR "LAST").

            BNZ     WAIT_FOR_CHANGE ;IF ALL 8 PINS ARE STILL THE SAME, LOOP BACK
                                    ;AND KEEP WAITING.

Does the 16C54A include a Change-on-PortB Interrupt capability?

No. None of the 16C5x PICs have any interrupts. 

What's the difference between the 16C54 and the 16C54A?

The only real difference is that the OTP 16C54s were pre-programmed with an oscillator type at the factory, while OTP 16C54As are classified by speed rating, and can be user-programmed to any of the oscillator types that support that speed.

For instance, the 16C54A-04 is rated for speeds up to 4 MHz; it can be user-programmed for RC or XT operation. The 16C54A-10 (rated for speeds up to 10 MHz) can be programmed for RC or XT operation up to 4 MHz, or HS operation to 10 MHz. The 16C54A-20 is rated for 20 MHz, and should only be used in HS mode. For LP mode, Microchip recommends the 16LC54A-04, which can be used up to 200 KHz.

The information in the previous paragraph isn't completely accurate. Actually, each of those chips will work in at least three oscillator modes; the -04 will do all 4 modes (but only up to 200 KHz for LP and 4 Mhz for the others), the -10 will do all but LP (but only up to 4 MHz for RC and XT modes), the -20 will also do all but LP (with the same RC and XT maximum-speed restrictions as the -10 part), and the LC54A-04 will do all but HS mode (but only up to 2 MHz in RC or XT mode). However, the parts aren't guaranteed to meet the databook's Min/Max specifications when they're used in these other modes (although they are tested for basic functionality), so it's probably best to stick to the oscillator-type recommendations in the previous paragraph. 

On the 16C84, can the EEADR register be changed immediately after initiating a write to the Data EEPROM?

No. The EEADR register's contents aren't latched; you must wait for the write to complete before changing EEADR. 

I just downloaded the new version of MPASM, and suddenly my code produces hundreds of "Using default destination of 1 (file)" messages. Why?

As you know, most PIC instructions can store the results in either the W register or in the source register. For a W-Reg destination, the instruction takes the form of, for example:
    ADDWF   REG,W
    or
    ADDWF   REG,0
For a source-register destination, the instruction looks like this:
    ADDWF   REG
    or
    ADDWF   REG,F
    or
    ADDWF   REG,1
These last three are equivalent, and most people just imply the source-register destination by using ADDWF REG.

The folks who man Microchip's Corporate Applications Tech-Support lines recently discovered that there are certain people in the world who are so brain-dead that they can't remember that ADDWF REG puts the result of the addition back in REG. For those people, Microchip has added (over the protests of MPASM's author, Kim Cooper) the "Using default destination...." message.

To keep those messages from appearing, put the following line at the start of your program:

    ERRORLEVEL -305

On the 16C74, I've set RA0 and RA1 as analog inputs and RA2-RA5 as digital outputs. When I use BCF or BSF to alter RA5, RA3 goes low. Why?

You've set up RA0 and RA1 as analog inputs, and I'm guessing that, because you don't want to use an external voltage reference, you've also set RA3 as an analog input (by writing xxxxx100 to ADCON1).

This is fine; RA3 can still be used as a digital output. The problem, though, is that whenever you READ from RA3, you'll see a "0".

The BSF and BCF instructions are read-modify-write instructions. That is, a BSF will read the entire port, change the appropriate bit, then write the entire port back.

When your BSF PORTA,5 instruction executes, it reads all of port A, including RA3 (which reads as "0"). It then sets RA5 and writes the value back, with bit 3 now cleared.

There are a bunch of ways to deal with this situation. The most straightforward is to make changes to a "shadow" of PORTA that you keep in a general-purpose register. After the changes are made, you can copy the contents of this register to PORTA with a MOVWF. If you use this technique, your code would look something like this:

    SHADOW  EQU     [any register]
    ....
            CLRF    PORTA           ;Initialize PORTA and its shadow.
            CLRF    SHADOW          ;
    ....
            BSF     RP0             ;Switch to register-page 1.
            MOVLW   00000011B       ;Set up PORTA2-5 as outputs.
            MOVWF   TRISA           ;
            BCF     RP0             ;Switch back to register-page 0.
    ....
            MOVF    SHADOW,W        ;Grab the shadow.
            IORLW   00100000B       ;Set RA5.
            MOVWF   PORTA           ;
            MOVWF   SHADOW          ;Make sure the shadow is still in
                                    ;sync with PORTA.
If you're using interrupts that write to or read from PORTA, you'll need to make sure that no interrupts occur while SHADOW and PORTA are out of sync, which is a pain, but other than that (and the speed/space penalty incurred by using a shadow register), the above solution will work fine. 

The 16C84 data book shows a minimum Watchdog Timer period of 7 milliseconds and a maximum EEPROM Write time of 10 ms. How do I ensure that the Watchdog Timer won't expire during EEPROM writes?

The 10-millisecond EEPROM write happens in the background; during the write cycle, your code will continue executing. While you wait for the EEPROM write to complete, you can reset the watchdog timer as often as you like. The following code fragment, for example, resets the watchdog timer every few cycles while waiting for the EEIF flag to be set:
    WAIT_FOR_EE:

            CLRWDT
            BTFSS   EEIF
            GOTO    WAIT_FOR_EE

The 16C5x has only a two-level stack. Microchip has an appnote which describes a way to simulate a larger stack in software, but it uses way too much RAM and time. Is there some other way?

One thing you can do, especially if a subroutine is called from only a couple of places, is replace the CALL/RETURN with something like the following:

Old way:

    CALL1   CALL    SUB
            ....
    CALL2   CALL    SUB
            ....
    SUB     NOP
            RETLW   0
New way:
    #DEFINE RETTO1  REG,0   ;If this bit is hi, "return" to CALL1.
                            ;Otherwise, "return" to CALL2.
    ....
    CALL1   BSF     RETTO1
            GOTO    SUB1
    ....
    CALL2   BCF     RETTO1
            GOTO    SUB1
    ....
    SUB1    NOP
            BTFSC   RETTO1
            GOTO    CALL1+2
            GOTO    CALL2+2
This uses only part of one register and a few extra instructions, and is much more efficent than simulating a full-blown stack. 

When I erase a PIC, it seems that the configuration fuses take much longer to erase than the rest of the EPROM. Is something wrong with my chip or eraser?

No. This is normal; it's a security measure which ensures that all code EPROM is erased before the Code-Protect bit. 

On the 16Cxx parts with built-in PWM generators, how do I use 10-bit resolution instead of eight-bit?

Think of the PWM as always using 10-bit mode internally, with a period of four times the 8-bit number in the period register, a duty-cycle of four times the 8-bit number in the duty-cycle register plus the two-bit number in CCPx X and CCPxY, and a basic time-unit of Tosc. That is, if you're using a 4 MHz oscillator, with the period register set to 100, the period will be 4 * 100 oscillator periods (4 * 100 * 0.25 microseconds), or 100 microseconds. If the duty-cycle register is set to 25 and CCPxX and CCPxY are both "0", the duty cycle will be 4 * 25 + 0 oscillator periods ([4 * 25 + 0] * 0.25 microseconds), or 25 microseconds.

CCPxX and CCPxY contain the two lowest-order bits of the 10-bit duty-cycle register. When you use "8-bit" mode, you're just setting those two low-order bits to "00", which effectively sets the PWM duty cycle to four times the number in the duty-cycle register. To use 10-bit mode, just put the low 2 bits of your desired duty-cycle in CCPxX and CCPxY, with the upper eight bits in the duty-cycle register. 

How can I perform a checksum on the PIC16 code space?

You can't; the PIC's Harvard architecture won't permit it. 

What C compiler would you recommend for PIC16/17 development?

I'd recommend MPC, from Byte Craft Limited (voice: 519 888-6911, fax: 519 746-6751, or BBS: 519 888-7626). It costs $700 or so.

There are other C compilers out there that are cheaper, but none are as complete and well-supported as MPC. MPC currently has a few bugs, and its code isn't as tight as that written by an expert assembly-language programmer, but it's still the best that's available.

You can download a fully-working (except for a generous limit on the size of the output assembly-code) demo copy of the compiler from Byte Craft's BBS. 

Is there a Windows-based simulator for the 16C5x?

Yes and no. There are a number of such simulators available, but none are as accurate and complete as Microchip's own DOS-based MPSIM simulator. MPSIM, however, is extraordinarily hard to use... Commands are entered as cryptic two-letter codes, the display isn't real easy to follow, etc.

Fortunately, Microchip is integrating MPSIM into their existing Windows-based MPLAB integrated development environment, which currently contains an editor, assembler, and emulator. They expect to have completed the integration by Spring, 1996.

"MPSIM-enabled" versions of MPLAB, like all of Microchip's currently-available development tools, will be made available at no charge. 

How do I use the FSR and INDF registers to indirectly access the PIC's registers?

It's real easy... Just load FSR with the register number, then read from or write to INDF. For instance, the following code will indirectly read the contents of register 05 and write to register 06:
        MOVLW   005H            ;POINT THE FSR AT REGISTER 5.
        MOVWF   FSR             ;

        MOVF    INDF,W          ;GRAB THE CONTENTS OF THE REGISTER
                                ;POINTED TO BY THE FSR.

        INCF    FSR             ;NOW THE FSR POINTS TO REGISTER 6.

        MOVWF   INDF            ;WRITE THE CONTENTS OF THE W-REGISTER
                                ;TO THE REGISTER POINTED TO BY THE FSR.

Can you explain the representation used in Microchip's appnotes for floating-point numbers?

Yeah, sure...

Floating-point values are represented by a two-number combination: a "mantissa" and an "exponent". For a floating-point value x,

       x = mantissa * (2 ** exponent),
where "**" means "raised to the power".

It's easy to see that there are an infinite number of mantissa/exponent combinations for any x. For example, all the following combinations give a result of 10 (decimal):

       10 * (2 ** 0)
       5 * (2 ** 1)
       2.5 * (2 ** 2)
       1.25 * (2 ** 3)
       0.625 * (2 ** 4)
       0.3125 * (2 ** 5)
Binary representation of numbers less than 1 work just like decimal fractions, except that the first digit to the right of the decimal point is the 1/2's digit, the next is the 1/4's, the next is the 1/8's, etc. If we convert the mantissas listed above from decimal to binary, we get:
       10 = 1010
       5 = 101
       2.5 = 10.1
       1.25 = 1.01
       0.625 = 0.101
       0.3125 = 0.0101
See a pattern?

Ok... There's a rule for choosing which of the infinite number of mantissa/exponent combinations to use. It's pretty simple: Find the mantissa with all 0's to the left of the decimal point and a "1" immediately to the right of the decimal point. That mantissa, with its corresponding exponent, is the one to use. Converting from one of the other combinations to that one is called "normalization", by the way.

In our case (floating-point representation for x = 10 decimal), we'd use 0.625 * (2 ** 4). Converting our mantissa and exponent to binary,

       mantissa = 0.101        exponent = 100
Everything clear so far? Good, because it gets a little tricky here.

Since the mantissa is, by definition, always 0.1xxxx..., we don't need to store the "0.1" portion of it. Instead, we'll just imply the "0.1" and make our mantissa contain only the bits which follow the "0.1".

"But wait," you ask, "What about negative numbers?"

Well, ok. Since we've saved a bit or two by not including the leading "0.1", we'll put the sign bit in the mantissa's most-significant (leftmost) bit position. For positive numbers, the sign bit is "1"; for negative numbers, the sign bit is "0".

After stripping off the "0.1", our mantissa is simply "01". Preceding it with the sign bit makes it "101".

Since math guys just can't leave well enough alone, the exponent gets messed with, too. They call it "biasing", and it's real simple: If "m" is the number of bits in the exponent (8 in our case), you just add 2 ** (m-1) to the exponent. After biasing the exponent for our example (and stripping / signing the mantissa), we have:

       mantissa = 101  exponent = 10000100
Since the PIC math routines use a 16-bit mantissa, the actual values are:
       mantissa = 1010000000000000     exponent = 100000100, or
       mantissa = 0xA000               exponent = 0x84
For -10 decimal, the mantissa is 0010000000000000 (note the leading "0" instead of "1"), or 0x2000, and the exponent is unchanged from the exponent for x = 10.

That's all there is to it.

For numbers between 0 and 1 (or between 0 and -1), it works exactly the same way. Reach back to your memory of high-school algebra class and remember that if y is a positive integer, then:

       x ** -y = 1 / (x ** y)
For example, 3 ** 2 = 9; 3 ** -2 = 1/9.

Applying this notion, we can see that the floating-point representation of, say, 1/10 is 0.8 * (2 ** -3). For x = 1/10, then, our mantissa and exponent are:

       mantissa = 0.8 (decimal)             exponent = -3 (decimal), or
       mantissa = 0.1100110011001100....    exponent = 11111101
Note that the exponent uses two's complement notation for negative numbers (0xFF = -1, 0xFE = -2, ..., 0x81 = -127, 0x80 = -128).

After stripping/signing the mantissa and biasing the exponent:

       mantissa = 1100110011001100             exponent = 01111101, or
       mantissa = 0xCCCC                       exponent = 0x7D
Oh, yeah... One more thing. For x = 0, the mantissa is 0 and the exponent is 0. In fact (because of the biasing), the exponent equals 0 only when x is 0.

Also, you may care that the PIC representation isn't exactly the same as the IEEE Standard; I don't. 

How do I do an 8-bit divide on a PIC16C5x?

Here's one way... It takes about 80 cycles. It can be easily modified to increase its speed and reduce its RAM consumption (Hint: DIVIDEND and QUOTIENT don't have to be separate registers), but in this form, it's probably adequate:
    ; 8-Bit Divide.  Written by Andy Warren.
    ;
    ; Copyright (C) 1994 Fast Forward Engineering.  All rights reserved.
    ; Permission is hereby granted for any non-commercial use,
    ; so long as this copyright notice remains intact.
    ;
    ; Enter with Dividend in DIVIDEND, divisor in DIVISOR.
    ;
    ; Exits with quotient in QUOTIENT and remainder in REMAINDER, DIVIDEND
    ; scrambled, DIVISOR unchanged, carry-flag set.

    DIVIDE  MOVLW   1
            MOVWF   QUOTIENT

            CLRF    REMAINDER

    LOOP    RLF     DIVIDEND
            RLF     REMAINDER

            MOVF    DIVISOR,W
            SUBWF   REMAINDER,W
            SKPNC

            MOVWF   REMAINDER

            RLF     QUOTIENT
            BNC     LOOP

Using a 16C5x (with no A/D converter) how can I measure the position of a pot?

Use a circuit like this:
+5V                   +--------------------------------+--------PIC I/O PIN
 |                    |                                |
 |        1K          V          10K                   |
 +-----/\/\/\/-----/\/\/\/-----/\/\/\/-----+          ===  0.1 uF
                     25K                   |           |
                                           |           |
                                          GND         GND
In your code, make the I/O pin an output and pull it low to discharge the cap. Then make it an input and measure the time it takes for the pin to read "1".

The PIC's 0/1 threshold changes with Vdd, and there's a part-to-part variation, but neither of those factors should affect your application much. 

How can I generate NTSC video sync, optionally synched to an external source, with a PIC16C71 running at 20 MHz?

Don't. If you must generate sync with a PIC, run it at 14.31818 MHz. You won't be able to sync to an external source, though... The PIC's interrupt latency won't allow it.

If I were you, I'd forget about using a PIC altogether, and just use off-the-shelf sync-separator and sync-generator chips. Everybody makes these things... Try National's LM1881 sync-separator and LM1882 sync-gen (or, if your sync source is less than perfect, you may want to use Elantec's separator). 

I need to generate precise delays using a PIC. How do I do this?

Use the following QuickBASIC program... It'll generate code for any delay up to around 12 billion cycles.

One thing to note: The program will compensate for the length of any code you want to place within the delay loop. However, it doesn't do this very intelligently when that user code takes more than half a dozen cycles or so. The generated code will still be accuately-timed, of course, but it won't look very pretty.

'
' Four-Variable PIC Delay Calculator, Version 4
'
' v1 - Written by Andy Warren.  31 Jan 1995
' v2 - Fixed the bug found by Eric Liu.  30 April 1995
' v3 - In order to make it easier to transcribe the
'      program from online sources, replaced all strings
'      of spaces with "q$(x)" string variables.  16 Sep 1995
' v4 - Fixed the bug found by Kalle Pihlajasaari.  23 May 1996
'
' (C) 1995-96 Fast Forward Engineering
'
' Permission is hereby granted for all
' non-commercial use.
'

        defdbl a-z

        dim q$(40)
        for x = 1 to 40
                q$(x) = ""
                for y = 1 to x: q$(x) = q$(x) + " ": next
        next

start:

        x = 0

        input "Number of cycles to delay:",delay

        input "Cycles consumed by user code within the delay loop:",user

        delay = int(delay): user = int(user)

        u$ = "; Your"+str$(user)+"-cycle code goes here."

        print

        if (delay - user) < 32 then print q$(34);u$: delay = delay - user: goto inline

        x = delay - 16 - user

        d = int(x/(256*(256*(256*(3+user)+2)+2)+2)): if d > 255 then d = 255

        x = x - d * (256*(256*(256*(3+user)+2)+2)+2)
        c = int (x/(256*(256*(3+user)+2)+2)): if c > 255 then c = 255

        x = x - c * (256*(256*(3+user)+2)+2)
        b = int (x/(256*(3+user)+2)): if b > 255 then b = 255

        x = x - b * (256*(3+user)+2)
        a = int (x/(3+user)): if a > 255 then a = 255

        x = a * (3+user)
        x = x + b * (256*(3+user)+2)
        x = x + c * (256*(256*(3+user)+2)+2)
        x = x + d * (256*(256*(256*(3+user)+2)+2)+2)

        x = x + 16 + user

        a = a + 1: b = b + 1: c = c + 1: d = d + 1

        if a = 256 then a = 0
        if b = 256 then b = 0
        if c = 256 then c = 0
        if d = 256 then d = 0

        a$=right$(q$(3)+str$(a),3)
        b$=right$(q$(3)+str$(b),3)
        c$=right$(q$(3)+str$(c),3)
        d$=right$(q$(3)+str$(d),3)

        print q$(7);"list r=dec"
        print
        print "r1";q$(5);"equ";q$(5);"[any file register]"
        print "r2";q$(5);"equ";q$(5);"r1+1"
        print "r3";q$(5);"equ";q$(5);"r2+1"
        print "r4";q$(5);"equ";q$(5);"r3+1"
        print q$(20);"___________________"
        print "delay:";q$(1);"movlw";q$(1);a$;q$(3);"|";q$(19);"|"
        print q$(7);"movwf";q$(2);"r1";q$(3);"|";q$(19);"V"
        print q$(7);"movlw";q$(1);b$;q$(3);"|";q$(7);"loop:";q$(2);u$
        print q$(7);"movwf";q$(2);"r2";q$(3);"|";q$(14);"decfsz";q$(1);"r1"
        print q$(7);"movlw";q$(1);c$;q$(3);"|";q$(14);"goto";q$(3);"loop"
        print q$(7);"movwf";q$(2);"r3";q$(3);"|";q$(14);"decfsz";q$(1);"r2"
        print q$(7);"movlw";q$(1);d$;q$(3);"|";q$(14);"goto";q$(3);"loop"
        print q$(7);"movwf";q$(2);"r4";q$(3);"|";q$(14);"decfsz";q$(1);"r3"
        print q$(11);"|";q$(7);"|";q$(14);"goto";q$(3);"loop"
        print q$(11);"|";Q$(7);"|";q$(14);"decfsz";q$(1);"r4"
        print q$(11);"|_______|";q$(14);"goto";q$(3);"loop"

inline:

        x = delay - x

        g = int(x/2): if g = 0 then goto inline1

        for y = 1 to g
        print q$(34);"goto";q$(3);"$+1"
        next

inline1:

        if x/2 = int(x/2) then goto finis

        print q$(34);"nop"

finis:

        end

How do I interface the PIC16C64/74's Parallel Slave Port to an ISA-Bus PC?

I assume that you've got a handle on the PIC end of things; it's pretty simple. If not, read Appnote #AN579, "Using the 8-Bit Parallel Slave Port", in Microchip's Embedded Control Handbook.

ISA-Bus interfacing is a little beyond the scope of this page... Get a copy of the best book on the subject, ISA & EISA Theory and Operation, by Edward Solari. It explains everything you'll ever need to know. 

Are there any undocumented bugs in Microchip's MPSIM simulator?

Probably, although Microchip makes every effort to fix bugs as they're reported. The latest version of the simulator (which runs under Microchip's Windows-based Integrated Development Environment, MPLAB) seems to have very few bugs.

If you've found what you think is a bug, you should report it to Microchip; they're very good at following up on these reports. 

I'm interfacing my PIC to AC power lines and need to protect it from power surges. What external circuitry should I use?

See the answer to Question #4, in the "Other Processors/Miscellaneous" section, below. 

I'm using an Apple Macintosh. What PIC development tools do you recommend?

MicroVention makes a complete set of development tools for the Mac; they can be reached at http://www.microvention.com/. Thanks to John E. Nelson for this information.

Francis Deck has a freeware PIC development system that includes an editor, assembler, and a "front panel" for an inexpensive PIC programmer, for which he also supplies full plans and firmware; details are on his web page at http://members.aol.com/fdeck/main.html.

If you prefer to use the PC-based tools available from Microchip, there are two ways: Buy a used PC or (if you have a suitably-powerful Mac) run Insignia Software's SoftWindows emulator on your Mac.

Jim Oslislo (joslislo@soho.ios.com), a Mac user, recommends the following configuration:

I'm using an IBM-compatible PC running Windows. What PIC development tools do you recommend?

Depends upon how much you want to spend. If you're a starving student or something, I'd recommend the following (all prices are in US dollars):
Microchip's MPLAB Integrated Development Environment is available from Microchip's BBS, web page, and ftp site. The PicStart Plus is available from any Microchip sales rep or distributor; it "plugs in" to MPLAB and will program all current and future PIC microcontrollers.

If you have more money to spend and want real-time hardware emulation, I'd recommend the following combination; if you're honest and pay the WinEdit shareware-registration fee, you'll have a decent development system for right around $1,000:

My only reservation about recommending the above system is that there are some bugs in the current version of the ICEPIC software. Fortunately, they're 1) relatively benign, and 2) being fixed by Microchip, so it's not all that bad. Sometime in the next year or so, Microchip will add ICEPIC support to MPLAB; when that happens, I'll be able to recommend the ICEPIC emulator without reservation.

Finally, if cost is no object whatsoever, I'd recommend the following system, which is what we use here:

The cost of this system is over $3,500. That's a lot of money, but as with most things, you get what you pay for. 

I've heard of third-party PIC programmers that cost as little as $15. Are they any good?

I have zero experience with those third-party programmers. Here are some things of which you should be aware, though:
  1. The very cheapest of these programmers will only program the PIC16C8x series.
  2. There are very few sub-$75 programmers that will program the PIC16C5x series.
  3. Most of these programmers assume that you already have a power supply and PC-to-programmer cable.
  4. Most are sold as kits.
  5. There's one more thing you should keep in mind if you're considering the purchase of any third-party PIC development tools, including assemblers, emulators, simulators, etc.:

    As dedicated as your third-party vendor may be, it's possible that he will eventually tire of updating his software or hardware, and you'll be left with tools that contain unresolved bugs and/or slowly become obsolete as new microcontrollers are introduced. This seems to be a particular problem with shareware tools written by people who always have a "day job" to go back to.

    Many third-party tool developers have introduced PIC development tools with great fanfare, only to drop support for them within a couple of years. Even the largest of the third-party suppliers are not immune.

    Microchip, on the other hand, will always support its silicon products with development tools. Those tools may not always be the best -- in fact, they may rarely be, since Microchip's primary focus is VLSI semiconductor manufacture, not tool design -- but I can live with that, because at least they'll be current.

    For more information on third-party development tools, see the companies listed in the "Embedded Systems Programming" section of our "Links" page

    I'm using a Microchip PRO MATE programmer. Occasionally, its "blank-check" feature tells me that a chip is blank, but the "verify" feature tells me that it's programmed. What's going on here?

    The PRO MATE's "verify" function verifies the contents of the chip at two voltages, Vdd min and Vdd max. The "blank check" function only reads the chip at one voltage. Occasionally, there'll be a discrepancy.

    If these chips are windowed EPROM parts, you should run them through a UV eraser; Microchip does not guarantee that windowed parts will arrive blank. If they're OTP parts, you should return them and/or your programmer. 

    Is it possible to generate a sequence of 8-bit pseudo-random numbers on a PIC?

    Yes. For most applications, the following Linear-Feedback Shift-Register implementation will be adequate. To use it, seed RANDOM with any non-zero value, then call the LFSR subroutine each time you want to change RANDOM to the next number in the sequence.
           LFSR:   RLF     RANDOM,W
                   RLF     RANDOM,W
                   BTFSC   RANDOM,4
                   XORLW   1
                   BTFSC   RANDOM,5
                   XORLW   1
                   BTFSC   RANDOM,3
                   XORLW   1
                   MOVWF   RANDOM
                   RETLW   0
    Here's another routine, written by Marv Isaacman:
           MARV:   MOVLW   01DH
                   CLRC
                   RLF     RANDOM
                   SKPNC
                   XORWF   RANDOM
                   RETLW   0

    How do I generate a CRC (Cyclic Redundancy Check) using a PIC?

    Try something like the following:
           CRCHI   EQU     some register
           CRCLO   EQU     another register
    
                   CLRF    CRCHI
                   CLRF    CRCLO
    
                   ;Append 16 "0" bits to your message here.
    
           LOOP    ;If there are no more bits in your message, go to
                   ;"DONE".  Otherwise, left-shift the next bit of your
                   ;message into the carry here.
    
                   RLF     CRCLO
                   RLF     CRCHI
    
                   SKPC
                   GOTO    LOOP
    
                   MOVLW   00100001B
                   XORWF   CRCLO
                   MOVLW   00010000B
                   XORWF   CRCHI
    
                   GOTO    LOOP
    
           DONE    ;The CRC is in "CRCHI" and "CRCLO".
    This isn't the fastest possible implementation, but it should be quick enough for most purposes. It uses the standard X.25 (and XMODEM) polynomial: x^16+x^12+x^5+1.

    You may also want to see the answer to Question #20, in the "Other Processors/Miscellaneous" section, below. 

    Can I write a routine that will generate various time delays which can be called from multiple points throughout my program?

    Sure. If you need, for instance, to generate time-delays of 1-256 milliseconds, you can use the following routines. When you need a delay, do the following:
                MOVLW   [some number]   ;THIS COULD ALSO BE A "MOVF [register],W".
                CALL    WAITMS          ;CALL THE "DELAY" SUBROUTINE.
    If you're using the 16C5x family, which doesn't have an ADDLW instruction, the "WAITMS" subroutine looks like this (I'm assuming that you're running at 4 MHz):
        MSTMR   EQU     [any register]
        MSTMR2  EQU     [another register]
    
        ;
        ; WAIT SOME NUMBER OF MILLISECONDS.  ENTER WITH NUMBER OF
        ; MILLISECONDS IN W (0 = 256).
        ;
        ; AT 4 MHz, 1 MILLISECOND TAKES 1000 CYCLES.
        ;
    
        WAITMS:
    
                MOVWF   MSTMR           ;MSTMR = THE NUMBER OF MILLISECONDS.
    
        WAITMS1:
    
                MOVLW   249             ;2-SETUP TO WAIT 1 MILLISECOND.
                MOVWF   MSTMR2          ;
    
        WAITMS2:
    
                NOP                     ;249-WASTE A CYCLE.  THIS COULD ALSO BE A
                                        ;"CLRWDT".
    
                DECFSZ  MSTMR2          ;746-
                GOTO    WAITMS2         ;
    
                DECFSZ  MSTMR           ;3-HAVE WE WAITED ENOUGH TIME?
                GOTO    WAITMS1         ;  IF NOT, LOOP BACK.
    
                RETLW   0               ;OTHERWISE, RETURN.
    If you're using a PIC whose instruction set includes the ADDLW instruction, you can save a register by rewriting the routine like this:
        MSTMR   EQU     [any register]
    
        ;
        ; WAIT SOME NUMBER OF MILLISECONDS.  ENTER WITH NUMBER OF
        ; MILLISECONDS IN W (0 = 256).
        ;
        ; AT 4 MHz, 1 MILLISECOND TAKES 1000 CYCLES.
        ;
    
        WAITMS:
    
                MOVWF   MSTIMR          ;STORE THE NUMBER OF MILLISECONDS.
    
        WAITMS1:
    
                MOVLW   249             ;1-SETUP TO WAIT A MILLISECOND.
    
                ADDLW   -1              ;995-WASTE 995 MICROSECONDS.
                SKPZ                    ;
                GOTO    $-2             ;
    
                DECFSZ  MSTIMR          ;HAVE WE WAITED ENOUGH?
                GOTO    WAITMS1         ;IF NOT, LOOP BACK.
    
                RETURN                  ;OTHERWISE, RETURN.
    Note that neither of these routines will give exact results, since they don't compensate for the CALL/RETURN overhead. They'll be accurate to within a couple of microseconds, though. 

    I'm writing macros in MPASM. How do I define labels within the macro so that they're given unique names each time the macro is invoked?

    It's easy... And you can define variables that are uniquely-named in each invocation, too. All you have to do is define the labels as "local". Here's how:
        ; THIS MACRO JUST WAITS UNTIL PORTA0 GOES HIGH.
    
        WAIT4A0 MACRO            LOCAL   TESTA0
    
    
        TESTA0  BTFSS   PORTA,0
                GOTO    TESTA0
    With TESTA0 defined this way, you can invoke the macro as often as you like, and MPASM will automatically select a unique name for the label in each case. 

    What is a PIC16C52? Is it pin-compatible with the 16C54?

    The 16C52 is a 16C54 with 384 words of code space, a narrower voltage range (3.0-6.25V versus the 16C54's 2.5-6.25V range), only two oscillator-type options (RC and XT, limited to a maximum speed of 4 MHz), and no Watchdog Timer (although is does still have the 16C54's 18-ms reset timer). It's available only in 18-pin DIP and SOIC packages.

    As far as I can tell, the PIC16C52 die is identical to the 16C54. If Microchip can figure out how to save money by manufacturing a chip with only 384 words of EPROM rather than 512, though, future 16C52s may actually be something other than crippled 16C54s. 

    The 16C73 and 16C74 can output in Pulse Width Modulation (PWM). How can I receive and decode this using another PIC?

    You can't.

    More precisely, I think you're misunderstanding the function of the PWM generator. The PIC's PWM output is a continuous stream of pulses, all identical, at a user-specified frequency and duty-cycle. I believe that you've confused this with PWM encoding of data, in which a finite string of "ones" and "zeros" are represented by long and short pulses. 

    Is there an automated way to convert code written for the PIC16C71 to the Motorola 68HC11?

    Nope. You could do a line-by-line translation, but you'd probably be better off rewriting the code. The 68HC11 is much more powerful than the PIC16C71, and code written specifically for it will be much more efficient than a brute-force translation. 

    How can I disassemble the code in a PIC?

    Most people who ask this question are up to no good. Fortunately, the rightful owners of the code they want to steal are usually smart enough to code-protect their PICs.

    If you're on the up-and-up and/or your PIC isn't code-protected, you can read the contents of the chip with any PIC programmer, then load the resulting ".hex" file into MPLAB and save the disassembled file that it creates. 

    What is the maximum current limit through the protection diodes on the PIC I/O ports?

    20 milliamps. 

    What's the difference, if any, between Byte Craft's MPC compiler and Microchip's MPLAB-C?

    Microchip licensed the MPC source code from Byte Craft Limited and used it as the basis for MPLAB-C. Contrary to popular opinion, Microchip did not "buy" MPC and simply rename it; Byte Craft will continue to market MPC.

    At this instant, MPLAB-C and MPC are nearly identical. As time passes, however, I'd expect the two compilers to evolve in different directions, with MPLAB-C becoming more memory-efficient and MPC growing to include more data types (including floats and 24/32-bit integers), more advanced math functions, etc.

    This prediction is my opinion only; please don't misconstrue it as representing the official plans of either Microchip or Bytecraft. 

    I'm trying to use pin RA4 on a PIC16Cxx and it doesn't seem to work properly. What's wrong?

    The RA4 pin (on most PIC16Cxx devices) is an open-collector output, so it can only drive low or tristate; it can not drive a high level. To make RA4 work like the other PortA pins, you need to hang a pullup resistor on it... Use a 10K or something. 

    I've never used interrupts before. I see that when TMR0 overflows, the T0IF bit is automatically set. If I have to poll that bit to see when it's set, how is this any different than simply polling TMR0 to see when it overflows?

    You're missing something basic. If interrupts are enabled, a TMR0 overflow will set the T0IF bit and [here's the important part] jump immediately to the interrupt vector (address 0x004).

    This is why it's called an "interrupt"; it interrupts the normal program execution, jumps to your "Interrupt Service Routine" (ISR) at address 4, executes the ISR, then returns to where it was before the interrupt and continues. 

    Is it possible to store data in an external memory (preferably SRAM) using a PIC16C84?

    It's a little tricky to use standard SRAMs, since they require so many interface pins for their Address and Data buses. Fortunately, you're not the first person to need something like this, so there are lots of solutions. If I were you, I'd take a look at Dallas Semiconductor's line of "RAMPort" parts; a link to Dallas Semi's web site is in the "Embedded Systems Programming" section of our "Links" page

    The PIC16C6X datasheet says that under certain conditions, Change-On-PortB interrupts may be missed. Is this true?

    Yes. If the change occurs just as PORTB is being read, the interrupt flag won't be set and no interrupt will be generated. What many people don't realize is that every instruction that accesses PORTB will read it.

    The upshot of all this is that you can't really depend on the Change-On-PortB interrupt to be reliable for anything other than waking-up the processor from sleep mode.

    Sucks, don't it? 

    Can you recommend a good book for a beginning PIC programmer?

    Yes... After a couple years of waiting, I finally can. David Benson has written a book called Easy PIC'n; it costs $29.95 and can be ordered from Square One Publishing (tel: 707 279-8881, fax: 707 279-8883).

    The book is written for complete beginners; no previous assembly-language programming is assumed. The book isn't intended to take its readers much beyond the beginning level, so most programmers with even moderate experience will find it too elementary, but for what it is, the book is excellent. Benson's style is light and conversational, and the book includes lots of clear examples. 

    I want to write code for the new PIC12C50x. What version of MPASM do I need?

    MPASM versions 1.40 and above support the 12C50x.

    Whenever you start using a new PIC, it'd probably be a good idea to make sure you have the latest assembler; the latest version of MPASM (as well as Microchip's other free development tools) can always be downloaded from the Microchip web page... A link to that page is in the "Embedded Systems Programming" section of our "Links" page

    How can I generate DTMF (Touch-Tone) tones using a PIC?

    It's pretty simple... The basic idea is to generate two sine waves (usually, by using a lookup table), sum them, then output a voltage proportional to the sum. That last bit can be accomplished either through an R2R ladder or by using a PWM pulse-stream.

    Sample code for generating DTMF tones is all over the web... I'd suggest looking at Eric Smith's page; there's a link to it in the "Embedded Systems Programming" section of our "Links" page

    I want to alter the contrast of a standard Hitachi-controller LCD display. Can I use PWM?

    Yes. If you're using a PIC that has a built-in PWM generator, this is really easy. If you're not, it's a little harder, especially if your PIC doesn't have interrupts, but it's not at all impossible.

    The key is to run your PWM frequency as fast as possible and to use a low-pass filter with a cutoff frequency as low as possible... LCD displays are pretty slow, but their internal refresh can "beat" with your PWM frequency if it's not filtered very well, leading to really awful flicker. 

    I'm running my PIC from two AA cells. I'd like to protect it in the event that the batteries are inserted backward, but I can't afford the voltage drop from a series diode. Any ideas?

    There are a couple of ways... Easiest, if you don't care about killing the batteries, is to put a diode across the battery terminals.

    The "better" way is to put a low-threshold N-channel FET in the negative lead (sourced to the negative terminal of the battery) and put a resistor between the gate and the battery's positive terminal, with a zener between the gate and source. I believe that this arrangement is patented by National Semiconductor. 

    I saw the 8-bit divide routine in Question #64, but I can't figure out how to extend it to divide one 16-bit number by another. How do you do a 16-bit divide?

    Like this. The following routine is written for clarity, not absolute speed, but it should still perform relatively quickly:
        ; 16-Bit Divide.  Written by Andy Warren.
        ;
        ; Copyright (C) 1996 Fast Forward Engineering.  All rights reserved.
        ; Permission is hereby granted for any non-commercial use,
        ; so long as this copyright notice remains intact.
        ;
        ; Enter with Dividend in DIVIDENDHI:DIVIDENDLO, divisor in
        ; DIVISORHI:DIVISORLO.
        ;
        ; Exits with quotient in QUOTIENTHI:QUOTIENTLO, remainder in
        ; REMAINDERHI:REMAINDERLO.
    
        DIVIDE16:
    
                CLRF    REMAINDERHI     ;CLEAR THE REMAINDER.
                CLRF    REMAINDERLO     ;
    
                MOVLW   16              ;WE'RE DIVIDING BY A 16-BIT DIVISOR.
                MOVWF   COUNT           ;
    
        DIVLOOP:
    
                RLF     DIVIDENDLO      ;SHIFT DIVIDEND LEFT 1 BIT INTO
                RLF     DIVIDENDHI      ;REMAINDERHI:REMAINDERLO.
                RLF     REMAINDERLO     ;
                RLF     REMAINDERHI     ;
    
                MOVF    DIVISORHI,W     ;COMPARE THE DIVISOR TO THE PORTION OF THE
                SUBWF   REMAINDERHI,W   ;DIVIDEND THAT'S BEEN SHIFTED INTO REMHI.
    
                BNZ     CHECKLESS       ;IF THE TWO HI-BYTES AREN'T THE SAME, JUMP
                                        ;AHEAD.
    
                MOVF    DIVISORLO,W     ;OTHERWISE, WE HAVE TO COMPARE THE
                SUBWF   REMAINDERLO,W   ;LO-BYTES.
    
        CHECKLESS:
        
                BNC     NOSUB           ;IF THE SHIFTED PORTION OF THE DIVIDEND WAS
                                        ;LESS THAN THE DIVISOR, JUMP AHEAD.
    
                MOVF    DIVISORLO,W     ;OTHERWISE, REMAINDER = REMAINDER - DIVISOR.
                SUBWF   REMAINDERLO     ;
                MOVF    DIVISORHI,W     ;
                SKPC                    ;
                INCFSZ  DIVISORHI       ;
                SUBWF   REMAINDERHI     ; (CARRY'S ALWAYS SET AT THIS POINT.)
    
        NOSUB:
        
                RLF     QUOTIENTLO      ;IF WE JUST SUBTRACTED, SHIFT A "1" INTO
                RLF     QUOTIENTHI      ;THE QUOTIENT.  OTHERWISE, SHIFT A "0".
    
                DECFSZ  COUNT           ;HAVE WE SHIFTED ENOUGH BITS?
                GOTO    DIVLOOP         ;IF NOT, LOOP BACK.
    
        ; AT THIS POINT, THE QUOTIENT IS IN QUOTIENTHI:LO AND THE REMAINDER IS
        ; IN REMAINDERHI:LO.

Motorola 6805

In the 68705P3/R3/U3, how is the "contents dump" feature invoked?

In general, 68HC705s are placed into "programming mode" by applying 9V to the IRQ pin, which forces the processor to fetch its vectors from addresses 16 bytes below the "normal" vector locations. However, on the P3/R3/U3 parts, programming mode is entered by applying 12V to the TIMER pin, which shifts the vectors downward by eight bytes.

For the P3, the "normal" vector locations are at $7F8-$7FF, so the "programming mode" vectors would be at $7F0-$7F7. For the R3/U3, the "normal" vectors are at $FF8-$FFF and the "programming mode" vectors are at $FF0-$FF7.

The "programming mode" RESET vector points to the built-in "bootstrap" code (at $785-$7F7 [P3] or $F80-$FF7 [U3/R3]), which handles all programming functions. Unfortunately, the P3, U3, and R3 parts do not contain bootstrap routines for "verify" or "contents dump".

For more information, see Motorola's application note #857, "MC68705P3/R3/U3 8-Bit EPROM Microcomputer Programming Module". 

Where can I find sample code for the 68HC05?

Try the FTP interface to Motorola Archives, at http://nyquist.ee.ualberta.ca/html/motorola.html

I'm learning Microchip PIC assembly language. Once I'm comfortable with it, will it be hard to learn Motorola 6805 assembly?

No, not very. Like the PIC, the 6805 is an accumulator-based machine; that is, all memory-to-memory transfers go through an internal register (which Microchip inexplicably calls "W" and all other manufacturers call "A"). The 6805 instruction set (although it uses different mnemonics) is really just a superset of the very limited PIC instruction set.

There are two big differences between the PIC and the 6805:


Other Processors / Miscellaneous

I'm writing a real-time clock/calendar program. How do leap-years work?

The algorithm is: Every year divisible by 4 is a leap year, unless it's divisible by 100 but not by 400.

1996 will be a leap year, since it's divisible by 4 and not by 100.

2000 will be a leap year, even though it's divisible by 100, because it's also divisible by 400.

2100 will not be a leap year, because it's divisible by 100 but not by 400. 

Where can I get a solid-state air-pressure sensor?

Call Motorola at 800 441-2447 and ask for their Pressure Sensor Device Data Book (literature #DL200/D). Without knowing anything at all about your application, I'd suggest that you look at their MPX5000 series. 

What's the phone number for DIGI-KEY?

1 800 DIGI-KEY. 

Do you have any advice on laying out PC boards for high-noise environments?

Get a copy of Intel's appnote #AP-125, "Designing Microcontroller Systems for Electrically Noisy Environments". It appears in many Intel handbooks; try the "Embedded Control Applications Handbook", literature order number 270648. 

What are Gray codes and how do I generate them?

Gray code is a sequence of binary numbers in which each number differs from the previous one by one bit only. Gray code, by the way, is a specific ordering. While many orderings may satisfy the requirement that each successive binary value differs from its predecessor in the value of only one bit, only one such ordering is the Gray code.

To form the Gray code for a sequence of consecutive numbers, take each number in the sequence, shift it right one bit, then XOR the result with the original number.

For example:

        Original                Gray Code
        Sequence             ((x >> 1) ^ x)
          (x)

          000                      000
          001                      001
          010                      011
          011                      010
          100                      110
          101                      111
          110                      101
          111                      100

I'm running Windows. What text editor do you recommend?

CodeWright, hands down. It's available from Premia Corporation (503 641-6000). 

Where can I get the Brief editor?

As far as I can tell, UnderWare (617 267-9743) originally developed the Brief editor, then sold it to SDC Software Partners II. It was published by Solution Systems (617 431-2313) for a while, and it now appears to belong to Borland International (800 336-6464). 

[Name deleted ] said that he could write what I think is a 4-week assembly-language program in only a couple of days. Can this possibly be true?

It's well-known that the difference in productivity between average programmers and real hotshots is enormous... Something on the order of ten- or twenty-to-one.

However, it's equally well-known that programmers, in general, have zero ability to estimate the time necessary to complete a job. Caveat emptor. 

I'm looking for a source of RF transmitters/receivers for a remote-control project. Any ideas?

DANGER! CAUTION! PELIGRO!

Potential-Conflict-of-Interest Warning:

I used to work for Linear Corp. While there, I designed their data-encoding and -transmission protocols and wrote the software for nearly all their products, so I may be a little biased here.

You have been warned.

There are a bunch of companies who make RF links, but I'd recommend the products manufactured by Linear Corporation. They sell a whole range of transmitters, from matchbook size on up, and a variety of super-regen and superhet receivers. They have versions for use in both North America and Europe, although they might not be type-accepted in Japan.

As an OEM customer, you can get the transmitters with or without encoders and the receivers with or without decoders. Of course, if you want to be FCC-legal, you'll have to either use their encoders or get yours type-accepted.

The domestic transmitter/receiver pairs are mostly in the 300 MHz range and the European ones are at 433.92 MHz.

Linear Corp. can be reached at 800 421-1587 or 760 438-7000. Ask for OEM Sales. 

I need to decode "RC5" commands from an infrared remote control. Where can I find information on this protocol?

Call your local Philips rep and ask for the "RC5 Remote Control System" specification... It even includes sample source code for the 8051. 

Do you have the name or number of a Ricoh distributor?

No, but you could call Ricoh Electronics at 714 250-7440 and ask them for the name of your local distributor. 

What are the relative merits of C versus Assembly-Language for microcontroller programming?

Wow... Big topic. Here are the first few thoughts that come to mind (in no particular order):

1. Good programmers can write good code in any language, and mediocre programmers will write crappy code in all languages. Writing in a high-level language makes it easy to avoid some "stupid" mistakes, but so does experience.

2. The nature of microcontroller programming is such that, often, very little code is reusable between applications. There are so many differences between one microcontroller-based project and another that similar algorithms must often be coded in wildly different ways, which is why the traditional reasons for writing in a high-level language (portability across platforms and reusability from one project to the next) are generally not reasons to use a high-level language to program small microcontrollers. There are reasons -- about 25% of the microcontroller code I write is written in C, for example -- but they have little to do with reuse.

3. Some problems are better expressed in C than assembly, and vice-versa. You've got to pick the right tool for the job.

4. Without a good understanding of the underlying assembly language, you won't be able to write optimal C.

5a. An excellent C compiler can generate better code than an excellent assembly-language programmer, because the compiler can safely generate incomprehensible, non-maintainable, "brittle" code that the programmer wouldn't dare write.

5b. An excellent assembly-language programmer can write better code than an excellent C compiler, because the programmer can see a much larger picture of the problem than the compiler can.

6. C is easier to debug. Compiler code-generation errors are rare, so debugging a C program involves mostly finding and fixing bugs in the program's design, rather than in its implementation. Since C offers a higher level of abstraction than assembly, you don't get bogged down in "can't see the forest for the trees"-type debugging.

7. Writing in C is faster than writing in assembly. I'm about the fastest assembly-language programmer I know, but I can write good C code even faster.

8. Because they're so easy to write and debug, programs written in C often suffer from massive "feature-creep".

9. With intelligent use of a really good macro assembler, you can have your cake and eat it, too. With an assembler that supports macros, multi-module code, long symbol-names, etc., you can write "C-like" (or BASIC-like, or... well, ok, not Lisp-like) macros that make assembly-language programming almost as easy as high-level programming.

10. If you spend your whole life honing your assembly-language skills, you won't be nearly as employable as any of the hundreds of thousands of C programmers out there. While C programs aren't always portable from one processor to another, C programmers are. 

I've heard that X-10 devices don't always work well. Is this true?

Yeah. There are a few things to look out for:

First, since they use the AC zero-crossings as a timebase, they don't work when the power goes out.

Second, they often don't work across circuits.

Third, there are some appliances (Sony TVs are the classic example) that do such excellent filtering of their incoming AC power that they suck the X-10 signal right off the power line. One Sony TV won't usually do it, but two or three in the same house will generally cause problems.

Fourth, X-10 is very slow... Simple commands can take a second or so to be executed, and complicated ones (like the sequence required to activate BSR's burglar-alarm sirens) can take many seconds. This isn't a problem for most typical X-10 applications. 

I need a high-accuracy 4 MHz crystal. Where can I get one?

For high accuracy, we've used 10-parts-per-million crystals from Ecliptek Corporation (714 433-1200). Aside from their frequency tolerance, they're pretty standard: 18 pF load capacitance, parallel resonance, AT cut.

10 parts per million, uncorrected in software, works out to an error of, at most, 5 minutes per year. If that's too much error for you, you can find people who make 5 ppm crystals. Instead of simply plating the crystals with silver, however, the manufacturer has to deposit a small layer of chrome or gold under the silver base plate, then vapor-deposit a final plate of solid gold over the whole thing. More manufacturing steps + more labor + higher raw-material cost = a very expensive crystal. 

I need to decode a Manchester-encoded data stream from a TV-type remote control. Want to write the program for me?

No, but I'll give you pseudo-code.

I'm assuming that your Manchester representation uses a gap/pulse sequence for "1" and a pulse/gap sequence for "0", and that the message begins with a couple of "1" start bits:

  1. Define the minimum and maximum widths for short (half-frame) and long (full-frame) pulses and gaps. Call these constants SMIN, SMAX, LMIN, and LMAX. It's likely that SMAX and LMIN will be equal.
  2. Wait for a pulse.
  3. Set a flag called FIRST_HALF to 1.
  4. Set a flag called "IF_SHORT" to 0.
  5. Load BIT_COUNT with the number of bits in the message.
  6. Wait up to SMAX for the end of the pulse (the message's first pulse is always short). If you don't see it after SMAX, exit.
  7. Start the TIMER.
  8. If IF_SHORT = 1 and you no longer see a gap, or if IF_SHORT = 0 and you do see a gap, go to step 9. Otherwise, go to step 10.
  9. If the TIMER has reached LMAX, exit. Otherwise, loop back to step 8.
  10. Invert the state of IF_SHORT.
  11. If TIMER is less than SMIN, or if TIMER is between SMAX and LMIN, exit.
  12. If TIMER is greater than LMIN, go to step 13. Otherwise, go to step 14.
  13. If FIRST_HALF = 0, go to step 16. Otherwise, exit.
  14. Invert the state of FIRST_HALF.
  15. If FIRST_HALF = 1, loop back to step 7. Otherwise, go to step 16.
  16. IF_SHORT contains the decoded value of the latest bit. Rotate it into your DECODE registers or whatever.
  17. Decrement BIT_COUNT. If it's still non-zero, loop back to step 7.
  18. Wait up to SMAX for the end of the final pulse (if any). If you don't see a gap after waiting SMAX, exit.
  19. You're done.
The "exit"s in steps 6, 9, 11, 13, and 18 represent error conditions (illegal start bit, pulse or gap too long, pulse/gap too short or between the short and long windows, no mid-frame transition, and final pulse too long, respectively).

When I say, "Start the TIMER", etc., in the description above, you can either use a hardware timer or a software loop-counter. I'd prefer the latter, but it'll work either way.

The IF_SHORT and FIRST_HALF flags may require a bit of explanation... FIRST_HALF simply tells us whether we're looking at the first half of a frame or the second. IF_SHORT is a little more complicated; it tells us three things:

Note that the first "1" start bit won't be rotated into your DECODE registers, since we don't get to step 7 and begin decoding until the start of the second frame. 

Have you ever considered authoring an article for [a popular electronics-engineering magazine]?

The last time I wrote for a magazine was in 1983. I don't enjoy that sort of "one-way" communication as much as the interactive conversations in which I participate online; even this web-based forum is more interactive than magazines.

Besides, it doesn't pay very well. 

I have a product based on the Hitachi 6303, which is being discontinued. Does anyone make a compatible processor? Can you point me to someone who could duplicate the 6303 in an ASIC?

You've got a problem; I know of no one who's still building 6301/6303 processors. We've done conversions from the 6305 to other processors, but the 6301/6303 isn't quite so easy.

I have a feeling that the cost to develop an ASIC would be greater than the cost to simply switch to another processor... Have you considered the Motorola 6805? Its instruction set is nearly the same as the 6303's (with the exception of the double-accumulator instructions, instructions which require a 16-bit index register, and a couple of the more obscure bit-test instructions) and many members of the 6805 family can access external ROM through a 64K address bus. 

I need a microcontroller with built-in OSD (On-Screen Display) and I2C-bus support. Any suggestions?

Yes. Look at the Motorola 68HC05T7 or 68HC05T10. 

What is a SAW transmitter, and how does it give you increased range over cheap tuned-L/C transmitters?

SAW stands for "Surface Acoustic Wave". A SAW transmitter is one that uses a SAW resonator (instead of a crystal or a tuned inductor/capacitor circuit) to set the transmitter's RF frequency.

SAW resonators don't inherently improve a transmitter's range. They do, however, keep its frequency from drifting. Since frequency-drift over time can be a primary cause of decreased-range complaints with tuned-L/C transmitters, this is a good thing.

SAWs aren't quite as accurate as crystals, but they cost a lot less and are certainly good enough to be used with the relatively wide-bandwidth receivers that they're usually mated to in car alarms, automatic garage-door operators, etc.

For all you ever wanted to know about SAWs, talk to RF Monolithics. They don't seem to have a web page, but you can call them at 214 233-2903 (fax: 214 387-8148). 

Where can I find a good description of CRC (Cyclic Redundancy Check) algorithms and theory?

The best explanation that I've ever seen was written by Ross Williams at Rocksoft Pty Ltd. It's called "A Painless Guide to CRC Error Detection Algorithms", and is subtitled, "Everything you wanted to know about CRC algorithms, but were afraid to ask for fear that errors in your understanding might be detected."

You can find it at ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt

What are Hamming codes, what do they do, and how can I use them?

Hamming Codes are a class of error-correcting codes developed by Richard W. Hamming. They're the best encoding scheme for single-bit error-correction in the presence of white noise (that is, they're designed for correcting errors in what's called a "binary symmetric" channel, where the odds of a "0" being incorrectly read as a "1" are the same as the odds of a "1" being read as a "0").

We use Hamming codes to ensure correct reception of radio data transmissions, to increase the effective endurance of EEPROM cells, etc.

In order to keep from boring you, I'm not going to discuss any of the math behind Hamming codes. If you'd like a rigorous mathematical explanation, there are plenty of discrete-math and error-control coding books available. One of the easiest to follow, by the way, was written by Hamming himself; it's called Coding and Information Theory (ISBN 0-13-139139-9). If you're a real glutton for punishment, you might also want to try to wade through Error Control Coding, by Lin & Costello (ISBN 0-13-283796-X), or An Introduction to Error Correcting Codes with Applications, by Vanstone & van Oorschot (ISBN 0-7923-9017-2).

Let's start with an analogy to binary error-correction. Instead of dealing with binary 1's and 0's, think about the problems of error-correcting English speech. If someone says, "base" and we hear "case", we accept the word, since "case" is in our language. This is the problem we face when we send binary messages without encoding; all combinations of 1's and 0's are allowed, so if a word has errors, we can't tell.

Fortunately, not all combinations of letters form valid English words. If you're reading English text and see "xase", you know there's an error (because "xase" isn't in the language), but you don't know whether the word should be "base", "case", or "vase". This is weakly analogous to the way that checksums and single-bit (odd or even) parity work.

The problem is that the words are too close together; only one letter separates the three words from each other. Even worse, the "b", "c", and "v" keys are adjacent on most typewriter keyboards. In order to correct the error, rather than just detecting it, we need some way to distance the words from each other, so that a large number of errors will have to be made before one word can be confused with another.

The "Alpha", "Bravo", "Charlie"... phonetic alphabet was developed for precisely this reason; none of the 26 words are similar to any of the others. If a pilot hears "Barley", he knows not only that an error occurred (since "Barley" isn't one of the 26 valid words), but he also knows the correct message, since the only word close enough to be incorrectly heard as "Barley" is "Charlie".

We can separate our words by adding a distinctive tag to each of them. Instead of saying "base" and "case", we could say "baseball" and "caseload". If someone hears "caseball", he knows it should be "baseball", since those two words are close (only one letter apart), while "caseball" and "caseload" are distant (four letters apart). He can mentally strip off the tag and safely assume that he should have heard "base".

Ok...

What Hamming did was to apply these ideas to binary messages. Here's how:

The "distance" between one string of binary digits and another is the number of digits in which the two differ. For example, the distance between 1011 and 1010 is 1. The distance between 1011 and 1101 is 2.

In order to correct all 1-bit errors (that is, 1 incorrect bit anywhere in the word), we need to construct a set of code words such that the distance between any two code words in the set is at least 3. Take a minute to understand why this is true.

By the way, a distance of 3 also allows us to detect all 2-bit errors.

Let's say we want to send 4-bit words. Without encoding, the minimum distance between any two of the 16 possible words is only 1. This is no good for us.

To separate the words further, we construct our code words by adding a 3-bit tag to each 4-bit word, like this:

       0000 becomes 0000 000   1000 becomes 1000 110
       0001 becomes 0001 111   1001 becomes 1001 001
       0010 becomes 0010 011   1010 becomes 1010 101
       0011 becomes 0011 100   1011 becomes 1011 010
       0100 becomes 0100 101   1100 becomes 1100 011
       0101 becomes 0101 010   1101 becomes 1101 100
       0110 becomes 0110 110   1110 becomes 1110 000
       0111 becomes 0111 001   1111 becomes 1111 111
If you have nothing better to do, you can examine the above list and see that no two 7-bit code words are closer than three digits.

There are sophisticated ways to decode Hamming codes using syndromes and large matrices. For a microcontroller application using a small Hamming code like this one, though, the following method is probably easier:

Upon receiving a code word, compare it to the code words in the list above. If it matches any of them, accept the first four bits of the code word. If changing the state of any single bit in the received code word produces a word that matches any in the list, change that bit, then accept the first four bits.

Note that proper decoding is not dependent upon error-free reception of the 3 tag bits... That is, there's no chance that an error in the tags will cause your decoding algorithm to erroneously "correct" an otherwise-good message.


[home] [about] [ask questions] (see answers) [garage sale] [links]


Sorry, you need graphics to see this.

We welcome your comments and suggestions. You can reach us by e-mail at: fastfwd@ix.netcom.com.
If you link your Web site to ours, please let us know.
Last modified 17 April 1998 by Andrew Warren.
Copyright © 1995-98 Fast Forward Engineering. All rights reserved.