Assembler PIC programming, is this correct?

Discussion in 'Embedded Systems and Microcontrollers' started by visaxx, Aug 14, 2013.

  1. visaxx

    Thread Starter New Member

    Aug 14, 2013
    9
    0
    Hello!! I have done some exercies / assignments but I dont have the correct answer for them. Can anyone please help me check if I have solved them correct? :) I would truly appreciate that.


    Question:
    implement the following pseudo code with assembly code:

    Code ( (Unknown Language)):
    1.  
    2. if (var1 > 9) or (var1 < 4)
    3. (increment PortC by 5)
    4. else
    5. (invert PortC)
    My answer:


    Code ( (Unknown Language)):
    1. movlw x09
    2. cpfslt var1
    3. goto add_5
    4. comf portC
    5. movlw x04
    6. cpfsgt var1
    7. goto add_5
    8. comf portC
    9.  
    10. add_5 movlw x05
    11. addwf portC

    Question:
    We want to send the ASCII-character 'B' with serial communication RS323 standard. The parity is odd. Draw the pattern in the following picture

    http://forumbilder.se/CF6Q7/133

    My answer:
    ASCII 'B' = 0100 0010
    http://forumbilder.se/CF6Q7/33a
    or should I swap the High and low bits before I draw the pattern?
     
  2. MaxHeadRoom

    Expert

    Jul 18, 2013
    10,555
    2,375
    There are many PIC's with built in USART now that it is a piece of cake to send RS232.
    PicMicro has an app note solely for USART function for each part category.
    Max.
     
  3. visaxx

    Thread Starter New Member

    Aug 14, 2013
    9
    0
    I'm studying for a test, so these methods is something I have to learn and to do..
     
  4. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    Presumably, this is for an 18F part (based on your use of the cpfslt instructions.)
    For A) Your logic is basically correct i.e. 4 < var1 < 9 will goto add_5. You need to add 'return' (if this is a subroutine) OR bra done (if inline) instructions at the end AND after the COMF or that code will run right into add_5, making a mess.
    Style pointers:
    Use bra instead of goto (smaller code)
    Always specify the destination register i.e. addwf PORTC,F for clarity and to remind you what you are doing.
    PortC is not a valid register using the standard register definitions, PORTC is (and never turn off case-sensitivity).
    Speaking of ports, when modifying outputs on an 18F use LATC, not PORTC to avoid the notorious read-modify-write problem.
    When you are using decimal numbers, specify them as .4 and .9, not x04 and x09. Either way works with these values.. until you change to x10 instead of .10
    Comments are your friend.
    Put your labels on a separate line and follow them with a colon i.e.
    Code ( (Unknown Language)):
    1. add5:
    2.  movlw .5 ; add .5 to the port
    None of the style things will impact the running of your code but you won't always be writing little things. Clean source is easier to read and find problems in.

    B)Your ASCII 'B' is 0x42 which is correct. For odd parity, you'll likely send 7 bits with the MSbit as parity (ODD,7,1) There are an even number of '1's in the data byte so the MSbit has to be set to make odd parity so its
    b'11000010'. When sending, the LSbit goes first so with a firmware UART you'll wind up shifting the byte to the right as you send the 8 bits, not swapping. Don't forget the start and stop bits.

    As Max says, a hardware USART is simpler in the real world, just compute the parity, drop the byte onto TXREG and you are done.

    You should be able to manually run through the code with pencil and paper. Pick a value for var1 and step through the code line by line until you get to the end. That would show problems like no return after the comf. Repeat with other values less than, equal to, between and greater than your test values. When the code flows on your desk, it will likely flow on the chip.

    Looks like you are on the right track.
     
    Last edited: Aug 14, 2013
    visaxx likes this.
  5. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    Want to do it slightly faster?
    Subtract 4 then see if the answer is greater than 5.
     
    visaxx likes this.
  6. visaxx

    Thread Starter New Member

    Aug 14, 2013
    9
    0
    Thank you, very clear explanation and useful tips! :)

    I have some more if you have time and don't mind take a look at them?

    Question:
    Type in the the new content after the asm-code have been executed.

    Code ( (Unknown Language)):
    1. Var1 equ x20
    2. Var2 equ x21
    3. Var3 equ x22
    4. Status equ x03
    5. VarA equ x28
    6. VarB equ x29
    7. VarC equ x2A
    8.  
    9. movfw Var1
    10. movwf Var3
    11. bsf status,w
    12. rrf Var3
    13. rrf Var3
    14.  
    15. movlw x3B
    16. addwf VarA,w
    17. movwf VarB
    18. xorfw VarC,1

    [​IMG]

    The left table is the memory-content before code execution and the left table is after. Does the 'after table' look correct?



    Question
    which ASCII-character is being sent? Method is serial communication with RS232. There is a stop bit, start bit, and a parity.

    [​IMG]

    My answer is 'b'. But I dont know if that is correct, I know that the startbit is always 0, and stop bit is always 1, then I am left with a space for 9 bits...

    [​IMG]
     
  7. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    Code ( (Unknown Language)):
    1. Var1 equ x20
    2. Var2 equ x21
    3. Var3 equ x22
    4. Status equ x03
    5. VarA equ x28
    6. VarB equ x29
    7. VarC equ x2A
    8.  
    9.  movfw Var1    ; 1ah->W
    10.  movwf Var3    ; 1ah->Var3  B'00011010'
    11.  bsf status,w    ; set CARRY - use bsf STATUS,C [I]not w. Yes w evaluates to 0 but what's THAT mean here?[/I]
    12.  rrf Var3    ; rotate Var3 right, carry->MSbit, carry out=0
    13.  rrf Var3    ; rotate again, 0->MSbit.  Var3 = B'01000110' 46h [B]OK![/B]    
    14.  
    15.  movlw x3B    ; W=3bh
    16.  addwf VarA,w    ; W=3bh+occh = (1)07h
    17.  movwf VarB    ; VarB = 07h  [B]OK![/B]
    18.  xorfw VarC,1    ; xorwf VarC,F  07h^0aah = 0adh ->VarC [B]OK![/B]
    I get 46h (ASCII 'F') for the serial. On the diagram left to right:
    1 - MARK condition, TX line is IDLE while MARK is true.
    0 - the start bit
    0110 - 6hex (backwards but it happens to be the same either way)
    0010 - 4hex (read it backwards as 0100)
    0 - 9th data bit, odd parity
    (1) stop bit

    The UART settings for this would be 8,O,1 8 data bits + 1 parity bit + 1 stop bit (+1 start bit) = 11 bit times total. Note that traditional ASCII is 7 bit data so parity (EVEN,ODD or NONE) would occupy the 8th bit (MSbit) for 10bittimes/character.

    Remember between start and stop, the parity is added at the MSbit end -AND- the data goes out LSbit first (right after the start).

    EDIT: if you read it the other way (start bit on the right), you get 62h which is ASCII 'b' but if the arrow is increasing time and the left-most 1 is the IDLE (the traditional way to draw it), its 46h.
    Also, the way it's drawn is correct from a LOGICAL viewpoint (MARK==1, SPACE==0) but if you measure the voltages on RS232 lines themselves, you'll find that the MARK is a (-)V and SPACE is (+)V. Something like a MAX232 is used to convert the RS232 to logic levels.

    BTW: you are mixing two different PICs in this thread. The first had to be an 18F because of cpfslt etc. This one has to be a midrange because of rrf (not rrncf or rrcf as in the 18F).
    Have fun!
     
    Last edited: Aug 14, 2013
    visaxx likes this.
  8. visaxx

    Thread Starter New Member

    Aug 14, 2013
    9
    0
    Just as before, thank you for very clear explanation and help! :)
    These are some mixed assignments/exercises from last year class and this year's class. Last year they used a 16F PIC and this year they are using a 18F, so that is why the instructions are mixed :)

    And I have some more exercises!
    Question:
    How long will it take for the following subrutin take if we use a 12 MHz crystal frequency on a F18 PIC?

    Code ( (Unknown Language)):
    1. hugo:
    2.  
    3. movlw .12
    4. movwf n
    5. goto test
    6. clrf n2
    7.  
    8. test:
    9. rrf n,W
    10. movwf PORTC
    11. nop
    12. return
    My answer:
    One instruction cycle will take 0.3333 ns, since (12Mhz/4)=3 --> invert 3 = (1/3) = 0.3333

    And we have 9 instructions cycles, so 9*0.3333 = 2.999 ns.


    Question:
    Write the following pseudo code with assembly code:

    if PORTC bit 2 == 1
    (increment var1 by 1)
    else
    (increment var1 by 2)



    My answer:

    Code ( (Unknown Language)):
    1. btfss PORTC,2 ;test if bit 2 is set
    2. goto add_2 ;skip if set
    3. incf var1,f ;add 1 to var1
    4. end
    5.  
    6. add_2:
    7. movlw .2 ; w = 2
    8. addwf var1,f ; var1 = var1 + w
    9. end

    Then there is a question that I dont really understand:
    What will the complete machine code instruction be and how long is the execution time expressed in cycles?

    Code ( (Unknown Language)):
    1. MOVLW 0x3A
    I understand that machine code is written in terms of 0 and 1. But how can I translate 'MOVLW' to binary form? Does it have something to do with the 'encoding' http://technology.niagarac.on.ca/staff/mboldin/18F_Instruction_Set/MOVLW.html
     
  9. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    I'd say 3ns, 2.999 is a rounding error.
    If you want to go faster:
    Add 1
    Check the port and add 1 if necessary.
     
    visaxx likes this.
  10. visaxx

    Thread Starter New Member

    Aug 14, 2013
    9
    0
    Thank you! Then I know it is 3 ns :)

    But what do you mean with add 1? Do you mean in question 2? I am supposed to add 1 or 2 depending on if PORTC,2 is set or not..
     
  11. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    Yes, question 2.
    The code becomes:
    Code ( (Unknown Language)):
    1. incf var1,f ;add 1 to var1
    2. btfsc PORTC,2 ;test if bit 2 is set
    3. incf var1,f ;add 1 to var1
    Same result, fewer instructions.
     
    visaxx likes this.
  12. visaxx

    Thread Starter New Member

    Aug 14, 2013
    9
    0
    Oh I see, that is a smart solution!
    But shouldn't it be btfss? Because if PORTC,2 is set we only want it to increase by 1.
     
  13. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    Good point, I got it the wrong way round.
     
  14. visaxx

    Thread Starter New Member

    Aug 14, 2013
    9
    0
    :)

    Here is another instruction cycle question, still with a 12 MHz frequency.

    Code ( (Unknown Language)):
    1. movlw .20
    2. movwf n
    3.  
    4. again:
    5. decf n,f
    6. bnz again
    7. nop
    8. nop
    9. rlncf n,w
    10. movwf PORTC
    11. nop
    12. return
    W have 68 instruction cycles, right? So my answer will be that it will take 22.66 ns which is about 23 ns. Or should I round down to 22 ns?
     
  15. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    Actually at 12MHz Tcyc is 333.33ns. 12/4=3MHz. → .333us. typing on phone.but wanted to point that out. so if it is 68 Tcyc your time is about 22.644 us. Looks like 68 to me too.
     
    Last edited: Aug 15, 2013
  16. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,690
    2,754
    Not entirely correct. In 8 bit math, the result of the subtraction from the values 0 through 3 will result in the values 255 through 252, which are all considerably greater than 5.

    Still need two tests. In this case, the first test should be of the carry flag after the subtraction.
     
    Eric007 likes this.
  17. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    Good point, there is a way of doing it with just one test, but there were a few ways of interpreting what I wrote in post 5, and the most of them would give the wrong answer.
    This way isn't much of a speed improvement, and it destroys var1, but I think it works.
    Code ( (Unknown Language)):
    1. movlw 4
    2. subwf var1, F
    3. movlw 6
    4. subwf var1, F
    5. btfsc STATUS, C
    6. goto com_portC
    7. movlw 5
    8. addwf PORTC, F
    9. goto done
    10. com_portC
    11. comf PORTC
    12. done
    13.  
    <ed> There is probably a way to knock a few cycles off using pic18 instructions </ed>
     
    Last edited: Aug 16, 2013
  18. visaxx

    Thread Starter New Member

    Aug 14, 2013
    9
    0
    Hello

    I have a question about the first assignment:
    Code ( (Unknown Language)):
    1. if (var1 > 9) or (var1 < 4)
    2. (increment PortC by 5)
    3. else
    4. (invert PortC)

    Code ( (Unknown Language)):
    1. movlw .9
    2. cpfslt var1
    3. bra add_5
    4. comf POTRTC
    5. movlw .4
    6. cpfsgt var1
    7. bra add_5
    8. comf PORTC
    9.  
    10. add_5:
    11. movlw .5
    12. addwf PORTC
    13. RETURN
    If var1 is greater than .9, then it will call add_5, and after the subroutin it will return to compf PORTC, and run the complement, even though we don't want it to..


    So maybe this will work better?:

    Code ( (Unknown Language)):
    1. movlw .9
    2. cpfsgt var1
    3. compf PORTC
    4. movlw .5
    5. addwf PORTC,f
    6. movlw .4
    7. cpfslt var1
    8. compf PORTC
    9. movlw .5
    10. addwf PORTC,f
     
  19. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    As far as I know, bra is like goto, and doesn't affect the call stack, so the RETURN at the end will return to the point immediately after the most recent CALL operation.
    It's the things that JohnInTX mentioned in post 4 that you have to worry about.
     
  20. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    I think someone already suggested something like this for checking if a number is inside or outside a range of numbers;

    Code ( (Unknown Language)):
    1.  
    2. ;
    3. ;       if (var1 > 9) or (var1 < 4)
    4. ;
    5.         movf    var1,W          ;
    6.         addlw   -(9+1)          ; test for [4..9] range
    7.         addlw   (9-4)+1         ; C=1 when 4 ≤ var1 ≤ 9
    8. ;
    9.  
    Here's an excerpt from a program where the method is used to decode a 12-bit Sony SIRC signal;

    Code ( (Unknown Language)):
    1. ;
    2. ;  collect sirc data, test for valid ~600-us high level followed
    3. ;  by a low level ~600-us '0' or a ~1200-us '1' data bit
    4. ;
    5. newbit
    6.         clrf    TMR0            ; clear TMR0, start measurement   |B0
    7. loophi
    8.         btfsc   PORTA,IR        ; pin lo yet? yes, skip, else     |B0
    9.         goto    loophi          ; loop (while timing hi pulse)    |B0
    10.  
    11.         movf    TMR0,W          ; pulse hi time (64-us ticks)     |B0
    12.         addlw   -(800/64+1)     ; test for ~600 ± 200 usecs       |B0
    13.         addlw   (800-400)/64+1  ; C=1 (400..800 usec range)?      |B0
    14.         skpc                    ; yes, skip (in range), else      |B0
    15.         goto    irloop          ; branch (abort & start over)     |B0
    16.  
    17.         clrf    TMR0            ; clear TMR0, start measurement   |B0
    18. looplo
    19.         btfss   PORTA,IR        ; pin hi yet? yes, skip, else     |B0
    20.         goto    looplo          ; loop (while timing lo pulse)    |B0
    21.  
    22.         movf    TMR0,W          ; pulse lo time (64-us ticks)     |B0
    23.         addlw   -(1500/64+1)    ; test ~600..~1200 ± 300 usecs    |B0
    24.         addlw   (1500-300)/64+1 ; C=1 (300..1500 usec range)?     |B0
    25.         skpc                    ; yes, skip (in range), else      |B0
    26.         goto    irloop          ; branch (abort & start over)     |B0
    27.  
    28.         addlw   -(900-300)/64   ; pulse <= ~900 usecs (a '0')?    |B0
    29.         skpnc                   ; yes, skip, else                 |B0
    30.         bsf     iradr,5         ; add a '1' bit to SIRC vars      |B0
    31.         clrc                    ;                                 |B0
    32.         rrf     iradr,F         ; shift entire 12 bits right      |B0
    33.         rrf     ircmd,F         ; and test the bit counter        |B0
    34.         btfss   ircmd,0         ; all 12 bits? yes, skip, else    |B0
    35.         goto    newbit          ; branch (collect next data bit)  |B0
    36.  
    37.         rrf     ircmd,F         ; fix 'ircmd' bit position        |B0
    38.  
    Hope the example helps. Good luck with your projects.

    Cheerful regards, Mike
     
    Last edited: Aug 18, 2013
Loading...