• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

16F: Proper Assembly Code Format Part 1

    Blog entry posted in 'Uncategorised', November 28, 2011.

    As a beginner first learning to code, some will have the tendency to start off being lazy. Their excitement gets the best of them and they just wanna make the thing work. Unfortunately this leads to the bad habit of becoming a 'sloppy' programmer, and writing sloppy code will just give you many unneeded problems in the long run as it will be near impossible to figure your code out when it comes to debugging it. Remember the saying "haste makes waste"? Well there's lots of truth to that statement.

    Here I will explain how to set up your assembly code for the 16F line of PICs as well as explain why we do each thing. Hopefully this will allow you to write clean/tight/well organized and optimized code that will be easy to read and follow once you reach the level of a proficient programmer.

    This article will be done in a series of multiple parts since the blogs limit me to 10,000 characters. With the code examples this lesson will far exceed that.

    The first thing to learn is how to comment your code. Comments are a blessing and should be used at all times. This helps you to know what each line of code is doing so that you don't lose your place as you go back to proof read your code.

    With the MPASM assembler as well as most other assemblers, the semicolon ( ; ) is used to place in a comment. The semicolon tells the assembler to ignore anything on the same line which follows it.

    Code:

    ;this is a generic comment to illustrate the
    ;use of the semicolon to place comments in
    ;your assembly code


    Now every programmer has their own style. In my style, I like to have a title bar on each section of code. Such a title bar can be done as such -

    Code:

    ;*************************************************************************************************
    ;** **
    ;** Title Bar **
    ;** **
    ;*************************************************************************************************


    Note the semicolons at the beginning of each line.

    Header Information

    The first thing to go at the very top of the code are directives for the assembler. Directives tell the assembler things like which processor the code is written for, where to find the header file which contains the names/labels of each special function register, what the default radix will be (decimal, hexadecimal, or binary), which assembler errors to suppress, and how to set the configuration word. These directives make up the section which we call the "Header Information" section.

    Using the 16F628A as the example, the header information section would look like this -

    Code:

    ;*************************************************************************************************
    ;** **
    ;** Header Information **
    ;** **
    ;*************************************************************************************************

    list p=16F628A, r=dec, w=-302
    include <P16F628A.INC>
    __config _LVP_OFF & _BOREN_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT

    ;Processor Type: 16F628A
    ;Default Radix: Decimal
    ;Error Level: Suppress Error 302
    ;Reference header file P16F628A.INC for SFR address and config word labels
    ;Code Protection Off
    ;Data Code Protection Off
    ;Low Voltage Programming Off
    ;Brown Out Reset Off
    ;RA5 is MCLRE
    ;Power Up Timer On
    ;Watchdog Timer Off
    ;Internal Oscillator - I/O on RA6/OSC2 and RA7/OSC1

    ;Fosc = 16MHz


    List Directive

    The list directive is the directive we use to tell the assembler the processor type, the default radix, and which assembler errors to ignore/suppress -

    p= Processor Type. In our example, we have told the assembler that the code is written for a PIC 16F628A processor.

    r= Default Radix. In our example, we have told the assembler that the default radix is decimal. This means that literal values that are in decimal radix do not have to be preceded with a radix identifier. If we don't set the default radix to decimal, then the assembler will assume that all values with no radix identifier are in hex and we would have to type the decimal value out in d'value' format. Example...if value = 25, we would have to type out d'25'.

    w= Assembler Error Level. In our example, we have told the assembler to ignore error number 302, which is an unneeded bank select warning that the assembler generates anytime it encounters instructions which alter the bank select bits RP1 and RP0 in the STATUS register. This is the ONLY error level we should have to suppress. If you encounter any other assembler errors besides error 302, there is something incorrect in your code.

    include

    The include directive points the assembler to the processor header file. The MPASM assembler comes included with a header file for every PIC processor. The header file contains an equates list that links each special function register address to a label which corresponds with the name of the register. This makes coding much easier as we don't have to memorize or look up the physical address of an SFR every time we want to access an SFR.

    The include file for each processor type is always titled P16FXXX.INC, with XXX being the digits in the processor number after the 16F.

    __config

    The __config directive tells the assembler what value to write to the configuration word of the PIC. The config word on most 16F PICs resides at ROM address 0x2007. On some 16F PICs, there will be 2 configuration words...one at address 0x2007 and one at address 0x2008. If no address is specified, the assembler will default to writing the configuration word to address 0x2007.

    The labels you see after the __config directive are also label equates that reside in the header file. Note that the underscore which precedes __config is actually a double underscore.

    Variable Declarations

    The next section of code is where we define our general purpose RAM address labels, which we call "variables". We do this with the "cblock" directive -

    Code:

    ;*************************************************************************************************
    ;** **
    ;** Variable Declarations **
    ;** **
    ;*************************************************************************************************

    cblock 0x70
    W_TEMP ;interrupt context save for W
    STATUS_TEMP ;interrupt context save for STATUS
    PCLATH_TEMP ;interrupt context save for PCLATH
    COUNT1 ;delay counter 1
    COUNT2 ;delay counter 2
    COUNT3 ;delay counter 3
    endc


    cblock stands for "Constant Block". This tells the assembler that we are defining a block of constants. The hex value which proceeds the cblock directive is the starting address for which to assign the labels which follow the cblock directive. In our example, the first label will point to RAM address 0x70, the second label will point to RAM address 0x71, the third label will point to RAM address 0x72, so on and so forth in sequence until it encounters the "endc" directive.

    I/O Pin Definitions

    The next thing is to place our labels which will point to I/O pins. You may ask "Why would we do this?". Simple. When we want to set a port output pin high/low or when we want to check a specific input pin, we can just reference the label which points to it. Well, what if for some reason we need to move a certain output or input to a different pin? Well, without the pin label definitions, we would have to find each and every instruction which addresses those pins and change which pin the instruction addresses. However, with the label definitions, all we have to do is change which pin the label points to, which makes things much more convenient.

    We accomplish this with the #define directive -

    Code:

    ;*************************************************************************************************
    ;** **
    ;** I/O Pin Definitions **
    ;** **
    ;*************************************************************************************************

    #define SDO PORTA,0 ;SPI bit bang Serial Data Out
    #define SCK PORTA,1 ;SPI bit bang Serial Clock
    #define LAT PORTA,2 ;latch strobe for 74HC595
    #define COMMON PORTB,0 ;common side of button switches
    #define CHANNEL PORTB,4 ;Vss drive for channel select button
    #define SOLO PORTB,5 ;Vss drive for solo boost select button
    #define FX PORTB,6 ;Vss drive for fx loop select button
    #define LEARN PORTB,7 ;Vss drive for learn mode button

    Comments
 

EE World Online Articles

Loading

 
Top