Continue to Site

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.

  • 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.

Help with serial echo 16F628

Status
Not open for further replies.

fiveten

Member
Hello,

First off I wanted to thank Nigel for his tutorials, I have used code that he has written as well as others from here and afar. Thank you all.

I am trying to build a RFID code lock and I am having troubles with my serial RX and TX asm code. I am using a rfid module that transmits 9600 bps 8-N-1. When I connect the RFID module to a usb serial port it will display data on my hyper terminal. After I added a 16f628a and the following code I no longer get a valid data stream to my hyper terminal. This is just a test asm to show that the Pic is receiving the data properly and transmitting it out properly. It doesn't work. Any feedback would be appreciated.

Thanks, Fiveten
 

Attachments

  • serial_com.asm
    2 KB · Views: 358
Lots of errors in your code. Try this version and see if it works.

A note about the UART...TRISB,RB6 & TRISB,RB7 BOTH need to be set to 1 to hand them off to the UART. I know most PIC tutorials would have you thinking different as they like to use the whole TRISbit = 1 = "Input" / TRISbit = 0 = "Output" and this convention can be very misleading in some cases...this one included.

All the TRIS bits do is turn the output drivers for each I/O pin on and off. Their logic is inverted as TRISbit = 1 = Output driver off while TRISbit = 0 = Output driver on. Truth be told that by writing all 0's to the port latch while switching the TRIS bits between 1 and 0, you can make the I/O pins behave like open drain outputs whether TRIS = 1 or 0.

But suffice to say that setting TRISB,RB6 and TRISB,RC7 to 1 will hand control of these pins off to the UART, and the UART will sort out the input/output functions for each.
 

Attachments

  • serial_com.asm
    3.7 KB · Views: 356
Last edited:
Thanks for the input.

Pommie, I am using a FT232/CP2102 TTL serial converter to interface with my PC. Is this not acting as a MAX232?

Jon, I see you added an interrupt handler code and streamlined the delay code. I'll have to learn about interrupts, as I know almost nothing about them. The datasheet shows RB1 and RB2 as the RX and TX Ports I have both set to input, is RB6 and RB7 also for UART control?

Thanks for all your help.
 
Hi fiveten (Rob Thielke?),

I spotted a mistake in your code which may be contributing to the problem. If you use a "return" instruction instead of a "retlw 0x00" instruction in your "Receive" subroutine you can avoid destroying the RX data in WREG.

Good luck on your project. Cheerful regards, Mike

Code:
Receive
        btfss   PIR1,RCIF       ; RX data? yes, skip, else         |B0
        goto    Receive         ; branch (wait for RX data ready)  |B0
        movf    RCREG,W         ; WREG = RCREG (RX data)           |B0
        retlw   0x00            ; WREG = 0x00                      |B0  <-- RX data in WREG destroyed

Send
        movwf   TXREG           ; send TX data                     |B0
        bsf     STATUS,RP0      ; bank 1                           |B1
Wait    btfss   TXSTA,TRMT      ; transmit complete?               |B1
        goto    Wait            ; no, branch (wait), else          |B1
        bcf     STATUS,RP0      ; bank 0                           |B0
        retlw   0x00            ;                                  |B0
 
Sorry...I was thinking of the 16F628A. I didn't realize the UART was on different pins on the two.

EDIT: It's been so long since I worked with the 16F628A that I forgot which pins the UART was on apparently. RB1/RB2 is in fact the UART on both of these.

That said...interrupts are just a hardware triggered subroutine (as opposed to software triggering with a call instruction), whether internally or from an external source. When I do UART receive routines, I always do them with the interrupt as the micro has no way to anticipate when it will receive data. Doing it through the interrupt allows you to have the code doing other things rather than waiting on data input.

On return instructions...unless I need the subroutine to return a value (like on table reads and what not) I always use the return instruction rather than the retlw instruction. As Mike stated, that prevents the data in W from being destroyed upon return.

On 16F PIC's, the program counter will jump to program address 0x0004 when an interrupt is triggered. You can either place the interrupt handler at this address or you can place a jump instruction (goto) here that jumps the PC to the interrupt handler. Interrupts are disabled by hardware when an interrupt is triggered. From here, you must check all of your interrupt flag bits to figure out which interrupt source triggered it, then jump it to the appropriate piece of code to execute for that interrupt. At the end of the interrupt handler, a retfie instruction (Return From Interrupt) returns the PC back to where it was pre-interrupt and also re-enables interrupts.
 
Last edited:
Thanks Mike,

I will try what you suggested, I think i see what you are saying. "retlw 0x00" is clearing w-reg as it returns?

PS. even though i am destroying the data, should I not get a hyper terminal screen full of "0" or what ever data is in "w"?

Sorry about the name change, I used a different computer and didn't realize i was logged in as myself from when I forgot my password.

fiveten
 
Thanks Jon,
I will try and integrate Interrupts into my project. Your code seems easy enough to follow.
 
I found a mistake in my code. Here's the corrected version. Your serial should work now.

You'll also notice I rewrote your delay routines. I include a 50mS delay, then a variable delay. To use the variable delay, you first load a value into W, then call it. The value you load in W will be how many times it calls the 50mS delay. Thus you can get a variable delay in 50mS increments.

If you need a 250mS delay, you first load the value of 5 in W, then call DelayVar.
 

Attachments

  • serial_com.asm
    3.7 KB · Views: 315
Last edited:
Jon, Thanks for the code and the delay routine.

Mike, I changed the retlw 0x00 to a return and i am getting a good valid data stream.

Thanks to all for your help.
 
Happy to hear you got it goin', Rob ('fiveten').

If you're interested... here's a relatively simple and versatile fixed delay subsystem for 14-bit core (16F) devices that allows you to specify 'cycle accurate' delays in cycles, usecs, or msecs with almost any clock. The subsystem uses one variable and memory overhead is 9 instructions for the "uDelay" subroutine and 4 instructions for each DelayCy() macro call.

Code:
        cblock  0x70
delayhi                 ; DelayCy() subsystem timing variable
        endc

;******************************************************************
;  K8LH DelayCy() subsystem macro generates four instructions     *
;******************************************************************
        radix   dec
clock   equ     4               ; 4, 8, 12, 16, 20 (MHz), etc.
usecs   equ     clock/4         ; cycles/microsecond multiplier
msecs   equ     clock/4*1000    ; cycles/millisecond multiplier

DelayCy macro   delay           ; 11..327690 cycle range
    if (delay<11)|(delay>327690)
        error " DelayCy range error "
    endif
        movlw   high((delay-11)/5)+1
        movwf   delayhi
        movlw   low ((delay-11)/5)
        call    uDelay-((delay-11)%5)
        endm

;******************************************************************
;  example code for simulation testing                            *
;******************************************************************
        org     0x0000
SimTest
        DelayCy(250*usecs)      ; <- put simulator PC here
        goto    $               ; <- put simulator break point here

;******************************************************************
;  K8LH DelayCy() sub-system 16-bit 'uDelay' subroutine           *
;******************************************************************

        nop                     ; entry for (delay-11)%5 == 4     |B0
        nop                     ; entry for (delay-11)%5 == 3     |B0
        nop                     ; entry for (delay-11)%5 == 2     |B0
        nop                     ; entry for (delay-11)%5 == 1     |B0
uDelay  addlw   -1              ; subtract 5 cycle loop time      |B0
        skpc                    ; borrow? no, skip, else          |B0
        decfsz  delayhi,F       ; done?  yes, skip, else          |B0
        goto    uDelay          ; do another loop                 |B0
        return                  ;                                 |B0

;******************************************************************
        end

Here's a simple delay subsystem usage example;
Code:
;******************************************************************
;  generate a precise 2000-Hz 'beep' for 32-msecs with almost     *
;  any clock (4, 8, 12, 16, 20 MHz, etc.).                        *
;******************************************************************
        radix   dec
beep
        movlw   128             ; 128 x 250 usecs = 32 msecs      |B0
        movwf   beepctr         ;                                 |B0
bloop   DelayCy(250*usecs-6)    ; 250-usecs minus 6 cycles        |B0
        movf    PORTA,W         ; read PORTA                      |B0
        xorlw   b'00000010'     ; toggle RA1 'Spkr' bit           |B0
        movwf   PORTA           ; toggle the 'Spkr' pin           |B0
        decfsz  beepctr,F       ; done? yes, skip, else           |B0
        goto    bloop           ; loop                            |B0
        return                  ;                                 |B0
Good luck on your RFID project...

Cheerful regards, Mike
 
Last edited:
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top