[PIC] 16F688 USART ISSUES

Oct 01, 2009 8 Replies

I=92m trying to get some PIC to PC communication going using the 16F688, but I am not having much luck.


Hardware setup is just a PIC16F688 with power, and RC4/RC5 connected to an RS232 ShifterBoard Kit from Sparkfun.

formatting link


I grabbed the code below off the internet somewhere. Nothing hooked up to the ADC but that=92s fine, I don=92t mind it spitting out random data, as long as it=92s the values in the registers. The code below compiles fine, load the chip, and start up hyperterminal. At 9600 baud 8 bits, no parity, no flow control I get nothing. If I lower the speed to 2400bps I get gobbledygook periodically at timed intervals corresponding to the RCV light on the serial shifter, so it looks like data is being transmitted. I assume I must just have the baud rate wrong.


In looking at the datasheet, for 9600baud, SYNC =3D 0, BRG16=3D1, BRGH=3D0 = I keep coming up with an SPBRG value of 8,000,000 / [16 (n + 1)] =3D



51.08 =3D [51]


The code I pulled used 25. I have had no luck with either setting. Anyone know what I am missing?


list p=3D16f688 ; list directive to define processor



#include ; processor specific variable definitions


__CONFIG _CP_OFF & _CPD_OFF & _BOD_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _FCMEN_OFF & _IESO_OFF


; '__CONFIG' directive is used to embed configuration data within .asm file.



; The labels following the directive are located in the respective .inc file.



; See respective data sheet for additional information on configuration word.


;***** VARIABLE DEFINITIONS



w_temp EQU 0x71 ; variable used for context saving



status_temp EQU 0x72 ; variable used for context saving



pclath_temp EQU 0x73 ; variable used for context saving


ADCH0 EQU B'00000001' ;setup ch 0, Vdd for Vref, and left justified result



ADCH1 EQU B'00000101' ;set to Ch1 same settings as above



ADCH2 EQU B'00001001' ;set to Ch2 same settings as above



ADCH3 EQU B'00001101' ;set to Ch3 same settings as above



COUNTER EQU 0x60 ;counter variable



TXPREBUF EQU 0x61 ;A buffer for the serial transmit buffer (a prebuf)



OCTTOVERT EQU 0x20 ;stores the a/d value when it's being converted to octal


;**********************************************************************



ORG 0x0 ; processor reset vector



goto main ; go to beginning of program


main


;***********************************************************



;Setup For 9600 bps tx serial interface



;***********************************************************



bsf STATUS, RP0 ;bank 1



movlw B'00111111' ;setup RC0-5 as inputs for serial i/ o and A/D



movwf TRISC



bcf STATUS, RP0 ;bank 0



bsf RCSTA, SPEN ;serial port enable



bsf BAUDCTL, BRG16 ;use 16 bit baudrate generator



bcf TXSTA, BRGH ;use low baudrate speed



movlw d'25'



movwf SPBRG ;setup baudrate generator



bcf TXSTA, SYNC ;asynchronous serial i/o



bsf TXSTA, TXEN ;enable transmission


;***********************************************************



;Setup A/D converter



;***********************************************************



bsf STATUS, RP0 ;bank 1



movlw B'00011111' ;Setup all of port A as inputs for A/ D



movwf TRISA



movlw 0xFF



movwf ANSEL ;Enable all available Analog channels



movlw B'01010000'



movwf ADCON1 ;Set 4uS conversion time w/ 4MHz internal clk



bcf STATUS, RP0 ;bank 0



movlw ADCH0



movwf ADCON0 ;AD: right justified result, ch 0, VDD ref. voltage



call WaitForAD


;***********************************************************



;Setup Timer1 for 1/10 second wait period



;***********************************************************



movlw B'00110001'



movwf T1CON ;load timer1 config register


GoAgain:



movlw 0x01 ;set to max for approx 1 sec delay



movwf TMR1L



movlw 0x00



movwf TMR1H



;bsf T1CON, TMR1ON ;start timer



bcf PIR1, TMR1IF ;clear overflow flag


;This is the delay between sample periods from the analog inputs



Wait:



btfss PIR1, TMR1IF ;check if timer has overflowed



goto Wait


call GetADValues


; loop through 4 values here and print them out



movlw 0x4 ;loop 4 times



movwf COUNTER



movlw 0x21 ;point to first a/d value



movwf FSR ;data pointer


OutLoop:



movf INDF, W ;getting indirect data



movwf OCTTOVERT ;store a/d value we need to convert


call TO_OCTAL ;convert currently selected A/D Channel to octal


movf 0x30, W ;output all bytes



movwf TXPREBUF



call SENDBYTE


movf 0x31, W



movwf TXPREBUF



call SENDBYTE


movf 0x32, W



movwf TXPREBUF



call SENDBYTE


movlw ',' ;do checking on this one to see if we're at the last byte



movwf TXPREBUF



call SENDBYTE


incf FSR ;goto next a/d value



decfsz COUNTER ;is counter zero yet? if so skip goto



goto OutLoop



; end of above loop


movlw 0x0A ;Line Feed (newline, hopefully)



movwf TXPREBUF



call SENDBYTE


;movlw 0x0D ;carridge return



;movwf TXPREBUF



;call SENDBYTE


goto GoAgain ;Reset the timer for another go around


;***********************************************************



;Subroutines



;***********************************************************


WaitForAD: ;wait 44us to init, 176 instruction cycles



movlw D'176' ;really only need 1/2 this many cycles due to test and set



movwf COUNTER



FourFourWait:



decf COUNTER



bnz FourFourWait ;keep decrementing until we reach 0


return


;get a/d values for 4 ch



GetADValues:



movlw 0x21 ;start of free ram



movwf FSR ;setup indirect addressing register


movlw ADCH0 ;goto channel 0



movwf ADCON0



bsf ADCON0, GO ;start conversion



btfsc ADCON0, GO ;conversion done?



goto $-1 ;keep looping



movf ADRESH, W ;get high byte into acc W



movwf INDF ;store adresh to 21h



incf FSR ;move ptr to 22h


call WaitForAD


movlw ADCH1 ;goto channel 1



movwf ADCON0



bsf ADCON0, GO ;start conversion



btfsc ADCON0, GO ;conversion done?



goto $-1 ;keep looping



movf ADRESH, W ;get high byte into acc W



movwf INDF ;store adresh to 22h



incf FSR ;move ptr to 23h


call WaitForAD


movlw ADCH2 ;goto channel 2



movwf ADCON0



bsf ADCON0, GO ;start conversion



btfsc ADCON0, GO ;conversion done?



goto $-1 ;keep looping



movf ADRESH, W ;get high byte into acc W



movwf INDF ;store adresh to 23h



incf FSR ;move ptr to 24h


call WaitForAD


movlw ADCH3 ;goto channel 3



movwf ADCON0



bsf ADCON0, GO ;start conversion



btfsc ADCON0, GO ;conversion done?



goto $-1 ;keep looping



movf ADRESH, W ;get high byte into acc W



movwf INDF ;store adresh to 24h


return


;convert to 3 octal bytes in ASCII



;stores bytes in 0x30 to 0x32, w/ lsb in 0x32 msb in 0x30



;input value stored in 0x20, ie OCTTOVERT



TO_OCTAL:



clrc ;clear carry



movlw B'00000111' ;bit mask field



andwf OCTTOVERT, W ;and with ADRESH



addlw 0x30 ;make this into an ASCII number



movwf 0x32 ;store result away



;octal byte 2



movlw B'00111000' ;bit mask field



andwf OCTTOVERT, W ;get 2nd set of 3 bits



movwf 0x31 ;place back into file



rrf 0x31 ;rotate to LSB, need 3x



rrf 0x31



rrf 0x31



movf 0x31, W ;now get it back



addlw 0x30 ;and add 30h to make a ascii number



movwf 0x31 ;store again



;octal byte 3



clrc ;clear carry



movlw B'11000000' ;bit mask field



andwf OCTTOVERT, W ;get last 2 bits



movwf 0x30



rrf 0x30



rrf 0x30



rrf 0x30



rrf 0x30



rrf 0x30



rrf 0x30



;btfsc 0x21, 0 ;check the LSB value from the last byte



;bsf 0x31, 2



movf 0x30, W ;get value back



addlw 0x30 ;convert to ASCII



movwf 0x30 ;store it


return


;transmit data on serial port



SENDBYTE:



btfss TXSTA, TRMT ;check tx buffer ready bit



goto SENDBYTE ;try again, keep polling


movf TXPREBUF, W ;get data from pre-buffer



movwf TXREG ;move data to tx register and start transmission


return


ORG 0x2100 ; data EEPROM location



DE 1,2,3,4 ; define first four EEPROM locations as 1, 2, 3, and 4


END ; directive 'end of program'


Don't want to appear obtuse, but the first mistake is to use hyperterminal if you're trying to debug serial comms. You can never be sure if it's really connected, or if it's locked up or whatever.

Have a look on the web for (windows) tera term. It's been around for years and is imho, the best free terminal package around. As well as being a rock solid terminal emulator, it also supports telnet sessions and the sources are free in C or pascal.

One less variable etc...

Regards,

Chris

That's no problem: Just connect the output and input of the serial shifter for a loopback without the PIC and hit some keys: if the connection works, you should see an echo, otherwise no echo of your keystrokes is displayed.

Frank Buss, fb@frank-buss.de http://www.frank-buss.de, http://www.it4-systems.de

Agreed, you can do that, but who has the time, especially if there's something around that just works out of the box ?.

No disrespect, but you need a hair shirt to want to use that piece of win 3.1 generation stuff...

Regards,

Chris

ter

ks,

ed.

There might be a hardware problem, or hardware handshaking may be enabled. Always worth doing a loopback if one is having issues.

Whatever terminal emulation programme you end up using the best peice of equipment to hang into a comms link is a break-out box. This will allow you to play with the connections, see what is and what isn't toggling when it should and gives you an easy point on which to hang a scope to check things out. Buy one or make one a very useful peice of kit for serial RS232 comms.

******************************************************************** Paul E. Bennett............... Forth based HIDECS Consultancy Mob: +44 (0)7811-639972 Tel: +44 (0)1235-510979 Going Forth Safely ..... EBA. www.electric-boat-association.org.uk.. ********************************************************************

Agreed, essential piece of kit. The work i've been doing for the past couple of years has a lot of serial comms at 9.6k (graphical road signs) and one of the most usefull bits of kit i've found has been the old HP protocol analyser series. Started with a blown power supply (fixed)

4955a which even has the hp basic option. Moved on to 4953, slightly smaller and eventually stopped at 4952's and a 4957a, all floppy drive. Now have 3 of the things courtesy of ebay at not much more the 10-20 ukp each, mine being the only bid. Have to tell myself to stop collecting every time another one appears :-).

You can monitor lines and program them to build just about any test pattern, wiggle rts dtr etc as well. Brilliant bit of kit and can't understand why hp dropped them from the catalog...

Regards,

Chris

I agree with you: 51 looks to be the correct value and not 25. 25 would be appropriate for 4MHz operation, not 8MHz which is what you are getting from the internal oscillator. Personally I wouldn't be too inclined to trust the internal oscillator anyway when RS-232 is involved but we will assume it is OK since I have no experience of that particular chip. The rest of your basic serial port set up also looks fine but I haven't gone right through the code listing

However, that incorrect value sets alarm bells ringing for me, as does another comment I noticed in the source abotu 4MHz operation. Where did you get this code listing from? It would be helpful to know so we could put it into context. I am guessing it was for a different chip? Code compatibility between different devices is generally poor in the PIC range and this may be causing issues. For example, since A/D is involved it is possible that you are not allowing sufficent time for conversions at the faster clock rate which may cause all kinds of strange behaviour. I'm not saying this is what is happening - as I said, I haven't been through the code in full, but if we know more about the origins of the code it would help to narrow down the issues.

Andrew Smallshaw andrews@sdf.lonestar.org

=3D0 I

Got the code right off the internet as is, it was orignally for the

16f688, which is why i grabbed it. I wanted to start with somthing I knew worked....only it didn't. Not sure if the original coder had problems with the int osc, but that is how they had it set up. 25 is the right value, 4MHz is the default clock speed for internal osc, unless configured to be 8MHz. I thought it was the other way around, but ended up catching it in the datasheet after a few glances at OSCON details. I ended up solving the problem by using a 4Mhz external crystal, and a value for SPBRG of 25. I didn't think there would be an issue with using the internal OSC, but apparently its worth it to go with somthing a little/lot more stable. Also using Tera Term Web, thanks for the suggestion ChrisQ. Much easier to work with than Hyperterminal for sure!

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required