I keep sending a desperate e-mail for help from this list, and I receive the mail back, it cannot be sent. I hope this one will pass :) My problem is that I try to use the hardware usart of the 16F628, but it doesn't seem to be working. To debug the code I put some leds to blink when it is transmitting or receiving data. Only the transmit led blinks at two keypresses, and after that, no blink. The receive led never blinks, so I assume the receiving is not functioning and the transmit buffer fills up. The initialisation code is:
From my point of view, the code is correct and it should function.
I'm sure it is a bug somewhere and hope you can give me a hint in this direction. Thank you.
> I keep sending a desperate e-mail for help from this list,
> and I receive the mail back, it cannot be sent. I hope this
> one will pass :)
It did :-)
Didn't the return mail had some clear-text error message ? That
should have told you what you did wrong. And you must have done
*something* different with this mail, right ?
> My problem is that I try to use the hardware usart of the
> 16F628, but it doesn't seem to be working.
[Code deleted]
I have no idea what language you are using. it's clearly not
MPASM like. You don't say, and I'm not going to guess.
> From my point of view, the code is correct and it should function.
Maybe, but you can never be 100% sure before you have checked the ASM
code produced by whatever tool you uses. Then write a short "pure" ASM
piece of code that does the same thing, and debug from that.
Jan-Erik.
PS.
I'd sugest that you try to make sure that your lines are about 70
chars long, either by configuring your mail tool, or just simply
by using the ENTER key now and then. That makes your posts much
easier replying to...
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
Sorry for the messy email message, I sent it from the webmail, and it has
an error :( I tried to send it from Outlook, but the SMTP server is not
functional at this time :( If you can view the message in HTML format it would appear correctly.
The code is written in C language for HiTech C Compiler, which is widely
used, so I didn't considered necessary to mention. The operations
for the initialisation of USART are basic, so the assembler code should be
no problem, considering that other code (for LCD and keypad) compiled
successfully.
Could it be any problem if I connected Tx to Rx to test the code ? I should get the characters sent back to Rx and from there to LCD, but nothing
arrives.
Lucian wrote:
> Could it be any problem if I connected Tx to Rx to test the code ?
Aha ! You did not tell us that either :-)
In general, I think it's much easier to debug USART code if you
use some *external* device (such as a terminal emulator on a PC,
or a RS232 line-listner).
Are you sure you get anything at all on the line connecting Tx and Rx ?
Have you checked with an o-scope ?
The blinking LED just says that your code *thinks* that it is sending
something...
Jan-Erik.
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
You wouldn't normally want to disable the transmitter in your ISR,
because the transmitter is still active after your ISR has finished
loading bytes into TXREG.
> sci_PutByte(sendbuffer[SendBufferPos]);
What does this function do? You don't need to call a function to
place a byte in TXREG.
--
John W. Temples, III
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
Thanks for the suggestions, now I adapted the code :)
In fact, now I put directly the value 25 in SPBRG, which is for 9600 baud rate, at 4 MHz (that's what I understood from a microchip application note). Is this value correct for my setup ? The TX interrupts are enabled when the send buffer has something and disabled when empty. The code for the ISR is inspired from an example from HT-PIC C Compiler, so I thought it is correct. If I deactivate the flag in the main loop, is it correct ?
I tried all this, but still, it is not functioning :( It acts like it ignores the serial part, the links are not blinking when they should (they are supposed to blink when a byte is transmitted). Any ideas are welcomed.
> In fact, now I put directly the value 25 in SPBRG, which is
> for 9600 baud rate, at 4 MHz (that's what I understood from
> a microchip application note). Is this value correct for my setup ?
Check your value using the *formulas* in the data sheet for your specific
PIC type ! And if you say that you have found the value in an app note,
why not tell us *what* app note (the ANxxx number) so we can check it ?
> The code for the ISR is inspired from an
> example from HT-PIC C Compiler, so I thought it is correct.
You might read the actual assembler code produced to verify that/if
your C code does the "right" thing.
And "inspiration" isn't a process without weak points :-)
Another way to debug is to strip your C code down until all
works. Built a very simple example without all the fancy
buffer handling. This also makes it easier to read the
assembler code produced. *Then* add the other features and
you'll probably see when it breaks.
Have you verified that the led*_on() and led*_off() routines
work as they should ? Why make them into separate routines ?
Isn't it just a simple bsf/bcf (or whatever it's called in C) thing ?
Jan-Erik.
PS.
Your posts are still composed of long lines
that makes it harder then necessarily to reply to...
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
part 1 1108 bytes content-type:text/plain; (decoded 7bit)
Lucian wrote:
> Check your value using the *formulas* in the data sheet for your specific
> PIC type !
Hi Lucian (and everyone),
If you have MS Excel, why not just use the Excel spreadsheet for calculating
SPBRG values I submitted last week?
For those that have missed it, I will attach it to this message. It's
definitely nothing special, but it can save you time and grief! No one
should be calculating SPBRG values by hand with a calculator over and over
again. There's just too many other fun things in life to do than doing this
manually -- that's why I made it. Just type in the Fosc in the
yellow-highlighted cell and you'll see all of the baud rates possible with
that Fosc -- in both high and low speed modes. But wait, there's more:
you'll also get your I2C clock frequencies as an added bonus.
And, if it is not to your liking, you can easily modify the spreadsheet.
Best regards,
Ken Pergola
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
part 2 19303 bytes content-type:application/x-zip-compressed; (decode)
Thank you, Ken, for the calculator, I tested the values with your Excel spreadsheet and indeed the value is 25. But I think it wouldn't be such a problem if the value is not so precise, because I think only the error level would be greater, but the transmission would still function. Is it correct ? Now, having set the correct baud rate, the program still doesn't want to function.
Please give me a hint of what is wrong. The code is:
Initialisation of USART:
unsigned char
sci_Init(unsigned long int baud, unsigned char ninebits)
{
BRGH = 1; /* high baud rate */
SPBRG = 0x19; /* set the baud rate */
I will try as Jan-Erik said to simplify the code and test it until it runs. The led procedures are correct, because I test them at the beginning of the program. I use procedures because I need to modify some bits in a status byte too. Do you guys see any mistake in this code ? Or any omission ? I am sure that if it is, you will see it long before me ;-)
Lucian
PS: It seems that the interrupts are not functioning and the ISR is not sending and receiving the data when checked RCIF and TXIF. I believe this because when i test sendbufferfull in ISR instead of TXIF & TXIE, it sends the data, but it isn't received, though Rx is connected to Tx. Why might this happen ?
>
> if(RCIF) {
> led2_on();
> receivebuffer[RecvBufferPos] = RCREG;
>
> if ((++RecvBufferPos)==MAXRECEIVEBUFFER) RecvBufferPos = 0;
> led2_off();
> }
> if(TXIF && TXIE)
> {
> led1_on();
> TXREG = sendbuffer[SendBufferPos];
> if ((++SendBufferPos)==MAXSENDBUFFER) SendBufferPos=0;
> led1_off();
> }
> sci_CheckOERR();
>
> I tried all this, but still, it is not functioning :( It acts like it ignores
the serial part, the links are not blinking when they should (they are supposed
to blink when a byte is transmitted). Any ideas are welcomed.
>
> Lucian
Even if this code works correctly you may not see the LEDs blinking because you
only leave them on for a very short time. They would have to be really bright
for you to notice them is they only blink a few times. Also the ambient lighting
would effect weather or not you can see them.
Regards
Sergio Masci
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
The problem is not whether the leds are blinking or not (in fact i can see the transmit led blink, but not the receive one). If she code should work correctly, i should have the keys pressed echoed back to the LCD -- which is not happening.
Lucian wrote:
> If she code should work correctly, i should have the keys
> pressed echoed back to the LCD -- which is not happening.
What keys and what LCD ? Has these been mentioned before ?
It seems that there are a number of things you havn't told
yet. Maybe a short description of the environment where this
piece of code is running would help others better understand
it ?
But maybe most important, make sure you can get the serial
communication (using your tools) to run *at all*, using the
smallest possible code piece. That would be much easier to
debug. *Then* add the bells-n-whistles like buffer management.
The LEDs could still be a good idea, thought...
Jan-Erik.
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
> No one should be calculating SPBRG values by hand with a calculator
> over and over again.
No one should be calculating them with calculators or spreadsheets or
JavaScript web pages or slide rules or looking them up in datasheets;
your compiler's preprocessor lets you implement the SPBRG calculations
in your code with no cost in code space, e.g.,
Of course, more elaborate schemes are possible that validate the above
macro generates a useful value and detect the appropriate value of
BRGH.
If I see code with
SPBRG = 25; /* 9600 baud */
the comment is worthless; I still have to verify the math. And then I
have to reach for my calculator/spreadsheet/whatever if I want to
change the baud rate or the system clock.
--
John W. Temples, III
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
I do not use interrupts anymore, because I already have a timer interrupt activated, and i think it is interferring. Anyway, I was disabling TXIE in the main loop.
I would like to know if there can be a problem if there are activated the timer interrupts and the usart module interrupts, and if I can still check RCIF to see if there is something to receive, or how could i figure it out.
Thank you very much for your answers.
> No one should be calculating them with calculators or spreadsheets or
> JavaScript web pages or slide rules or looking them up in datasheets;
> your compiler's preprocessor lets you implement the SPBRG calculations
> in your code with no cost in code space, e.g.,
Valid point and I agree with you, but when you are at a point where you have
not selected a crystal for a project, working with the spreadsheet to see
*all* possible baud rates for a particular crystal is very convenient. It
lets you easily play out "what if" scenarios very quickly.
Is there a way to do this with MPASM or Hi-Tech's C preprocessor (print out
*all* of the baud rates possible given Fosc)? If there is an easy way, that
would be great.
Regards,
Ken Pergola
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
I do not see you clearing TXIF or RCIF -- if you do not clear TXIF or RCIF
after you process the first interrupts they cause, you will get recursive
interrupts.
Regards,
Ken Pergola
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
> Is there a way to do this with MPASM or Hi-Tech's C preprocessor (print out
> *all* of the baud rates possible given Fosc)? If there is an easy way, that
> would be great.
I can't think of any way that would be possible with a C preprocessor
since it doesn't support the notion of displaying "variable" data. I
ended up writing a C program to dump out just the kind of "overview"
for a given Fosc that you're talking about:
> I do not use interrupts anymore, because I already have a timer
interrupt activated, and i think it is interferring.
Interrupts don't "interfere" with each other.
> I would like to know if there can be a problem if there are
activated the timer interrupts and the usart module interrupts
Not from the PIC, if that's what you mean.
> and if I can still check RCIF to see if there is something to receive, or how
could i figure it out.
You only need to check RCIF in your interrupt handler.
It sounds like you have too much going on your code that you don't
understand; I would suggest taking the advice others here have given
and step back to a simpler example. An polled serial echo is very
trivial to implement, and you can verify it by typing into your PC
communications program; this also verifies your serial hardware and
your UART settings. Then you can move to an interrupt-driven serial
echo, then on to a buffered, interrupt-driven serial scheme.
--
John W. Temples, III
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
Ok, here's a couple of stupid questions: you say you have looped transmit back
to receive
1... are you sure transmit is actually connected to receive
2 ... is anything else connected to either transmit or receive
(perhaps interfering with the transmit)
> The problem is not whether the leds are blinking or not (in fact i can see the
transmit led blink, but not the receive one). If she code should work correctly,
i should have the keys pressed echoed back to the LCD -- which is not happening.
>
> Regards,
>
> Lucian
>
> {Original Message removed}
> On Sat, 4 Oct 2003, Lucian wrote:
>
> > I do not use interrupts anymore, because I already have a timer
> > interrupt activated, and i think it is interferring.
>
>Interrupts don't "interfere" with each other.
Well, it depends on how you look at it and how you have written
your ISR (and how you define "to interfere" :-) ).
Lets say you have to interrupt sources "A" and "B",
two "enable flags" "AE" and "BE", and two "interrupt flags"
"AF" and "BF".
Now, lets say that both A and B are handled by the ISR. You
probably start your ISR with a "dispatcher" that checks the AF
and BF flags and jumps to the correct code. Perhaps first
checking AF and then BF.
Now, you want to "stop" the interrupt handler for A so you clear
the AE flag. All seems to be well, the event A will not trigg
the interrupt handler. But, the AF flag will still be set whenever
the event A happens.
Later on the event B sets BF and triggs the interrupt. Now, since
the AF flag is now set, the ISR "dispatch" code will see this and
call the A interrupt handler.
This is of course "cured" by checking both the "F" and "E" flags
in the ISR dispatcher, but I'm sure many has been trapped by
this, I have at least... :-)
The other cause of "interferance" I can think of, is if one
ISR handler just takes to much time so the other event is missed.
So, to me, it's clear that interrupts can "interfere".
My current desig with a 12F629 @ 4Mhz has three interrupt sources
running at the same time, GIPO-on-change, GP2-int, and tmr0
overflow. Two of them at about 100Hz and the third in bursts
at about 1 Khz. Works great. The ISR just make a few checks and then
sets some flags that are checked in the main loop. All real
processing is done as code dispatched from the main loop. I'm using
assembler so I have full control...
> > I would like to know if there can be a problem if there are
> > activated the timer interrupts and the usart module interrupts
>
> Not from the PIC, if that's what you mean.
It depends on what the timer interrupt does. If it take to long time,
the USART might overrun. I'd call that to "interfere".
> > and if I can still check RCIF to see if there is something to receive, or how
> could i figure it out.
>
> You only need to check RCIF in your interrupt handler.
Yes, but if the RC-interrupt is disabled by clearing RCIE, you
have to check the RCIF flag regulary in your main code. One have
to decide...
> It sounds like you have too much going on your code that you don't
> understand; I would suggest taking the advice others here have given
> and step back to a simpler example. An polled serial echo is very
> trivial to implement, and you can verify it by typing into your PC
> communications program; this also verifies your serial hardware and
> your UART settings. Then you can move to an interrupt-driven serial
> echo, then on to a buffered, interrupt-driven serial scheme.
Amen to that !
Jan-Erik.
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
On Sat, 4 Oct 2003, Jan-Erik Soderholm XA (TN/PAC) wrote:
> > > I would like to know if there can be a problem if there are
> > > activated the timer interrupts and the usart module interrupts
> >
> > Not from the PIC, if that's what you mean.
>
> It depends on what the timer interrupt does. If it take to long time,
> the USART might overrun. I'd call that to "interfere".
I don't equate "interrupt" with "interrupt handler." Enabling the
timer interrupt will not interfere with the PIC's delivery of the UART
interrupt, which is how I understood the OP's question. If your
handler is broken, that's another issue.
--
John W. Temples, III
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
> If you have MS Excel, why not just use the Excel spreadsheet for
> calculating SPBRG values I submitted last week?
Because then you still just end up with hard coded constants in your code,
even if they are more likely to be right.
In my opinion, the best answer is to have the assembler calculate the
SPBRG value from the oscillator frequency and the desired baud rate. This
is what my UART_BAUD macro does, in addition to some error checking and
handling of different PIC UART variants. The UART_BAUD macro is available
in STD.INS.ASPIC at http://www.embedinc.com/pic.
*****************************************************************
Embed Inc, embedded system specialists in Littleton Massachusetts
(978) 742-9014, http://www.embedinc.com
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
> Thank you, Ken, for the calculator, I tested the values with your Excel
> spreadsheet and indeed the value is 25. But I think it wouldn't be such
> a problem if the value is not so precise, because I think only the
> error level would be greater, but the transmi Please give me a hint of
> what is wrong. The code is:
Why not figure this out in assembler so that you (and those helping you)
can see exactly what it going on? Personally I think it's a waste of time
trying to figure this out with a big unknown like the compiler between
your code and the real code.
You can also look at my QQQ_UART.ASPIC template module at http://www.embedinc.com/pic for a complete and known working UART handler
that does interrupt driven I/O and has send and receive software FIFOs.
*****************************************************************
Embed Inc, embedded system specialists in Littleton Massachusetts
(978) 742-9014, http://www.embedinc.com
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
> Because then you still just end up with hard coded constants in your code,
> even if they are more likely to be right.
Hi Olin,
No problem here, I totally agree with you and others regarding the point of
having the assembler or the C compiler generate the value for SPBRG. It's
definitely a method of "working smarter" vs "working harder".
I remember seeing some posts indicating there were errors in the data
sheets, and references to "use the formula" etc. I was envisioning people
getting out their calculators and manually going through iterations of SPBRG
calculations.
Why? Because I used to do that of course! :)
Even though I'm guilty of it myself, I wasn't advocating using hard-coded
SPBRG constants in the source code, but rather I was advocating using the
spreadsheet as a tool for what it does best -- quick, *multiple*
calculations, and "what if I change Fosc" scenarios.
A lot of times I have a pool of crystals to choose from and I want to
quickly see if they produce standard 0% error baud rates or not. Or when
dealing with the MSSP, I want to see what I2C clock frequencies are
available to me with a certain crystal frequency. These are prime examples
where having a spreadsheet puts all the info in front of your face quickly
and greatly aids in design decisions.
Best regards,
Ken Pergola
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
I hope you are making some progress.
I agree with the advice of others regarding simplifying things.
Maybe try this "minimalist" approach for now:
(Use Hi-Tech C, but do not use interrupts for now.)
Step 1) Use a software terminal emulator on a PC -- configure it for 9600
bps.
Step 2) Before involving the PIC, test the PC side of things by doing a
simple loop back:
Short the TX and RX pins on the serial cable connected to the PC and
type on the keyboard.
You should see an echo of what you are typing.
Step 3) Use a MAX232 device between the PIC and the PC (don't forget your
ground connection).
Step 4) Configure the PIC to 9600 bps and transmit "Lucian" to the PC.
This is very simple to do -- but once you have completed that task, you will
have proven a lot.
Just think of this as sort of a "blinking LED" program for the PIC UART.
Very little code, keep things simple.
Then, when the above works fine, you can work on the PIC receiving
characters from the PC.
If you need *any* help with the above, don't be afraid to ask -- many of us
on this list would be willing to help you out. There's nothing better than
seeing people get beyond their current problem when they are up against a
brick wall.
What do you think?
Regards,
Ken Pergola
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
> Hello guys,
>
> I keep sending a desperate e-mail for help from this list, and I receive the mail back, it cannot be sent. I hope this one will pass :) My problem is that I try to use the hardware usart of the 16F628, but it doesn't seem to be working. To debug the code I put some leds to blink when it is transmitting or receiving data. Only the transmit led blinks at two keypresses, and after that, no blink. The receive led never blinks, so I assume the receiving is not functioning and the transmit buffer fills up. The initialisation code is:
>
> tmp = 16UL * baud;
> X = (int)(XTAL/tmp) - 1;
> if((X>255) || (X<0))
> {
> tmp = 64UL * baud;
> X = (int)(XTAL/tmp) - 1;
> if((X>255) || (X<0))
> {
> return 1; /* panic - baud rate unobtainable */
> }
> else
> BRGH = 0; /* low baud rate */
> }
> else
> BRGH = 1; /* high baud rate */
> SPBRG = X; /* set the baud rate */
>
> SYNC = 0; /* asynchronous */
> SPEN = 1; /* enable serial port pins */
> CREN = 1; /* enable continuous reception */
> SREN = 0; /* no effect - in asyncronous don't care*/
> TXIE = 1; /* enable tx interrupts */
> RCIE = 1; /* enable rx interrupts */
> TX9 = ninebits?1:0; /* 8- or 9-bit transmission */
> RX9 = ninebits?1:0; /* 8- or 9-bit reception */
> TXEN = 1; /* enable the transmitter */
>
> And the ISR routine:
>
> if(RCIF) {
> led2_on();
> receivebuffer[RecvBufferPos] = sci_GetByte();
> if ((++RecvBufferPos)==MAXRECEIVEBUFFER) RecvBufferPos = 0;
> led2_off();
> }
> if(TXIF && TXIE)
> {
> led1_on();
> if(SendBufferPos == SendBufferRecPos)
> TXEN = 0;
> else
> sci_PutByte(sendbuffer[SendBufferPos]);
> if ((++SendBufferPos)==MAXSENDBUFFER) SendBufferPos=0;
> led1_off();
> }
> sci_CheckOERR();
>
>>From my point of view, the code is correct and it should function.
> I'm sure it is a bug somewhere and hope you can give me a hint in this direction. Thank you.
>
> Lucian
>
Hi Lucian,
I do not see the following lines after you finished the usart
initialization in your main function:
PIR1 = 0; /* clear any pending interrupts */
PEIE = 1; /* enable peripheral interrupts */
GIE = 1; /* global interrupts enabled */
I included the file sci.txt which you can find in x:\HT-PIC\samples\usart
Hope this helps,
Gaston
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
part 2 5616 bytes content-type:text/plain; name=sci.txt; CHARSET=US-ASCII (decoded 7bit)
The sci functions and macros to implement asynchronous
communication on the Serial Communication Interface (SCI)
module.
CONTENTS
########
1 Setting Up
2 Asynchronous Function Definitions
3 Examples
4 Using Interrupts
1) Setting Up
#############
The file sci.h should be #included into your source
files. This file contains a macro which specifies
the Fosc frequency. This affects the baud rate
calculations and should be adjusted to suit your
application.
2) Asynchronous Function and Macro Definitions
##############################################
unsigned char
sci_Init(unsigned long int baud, unsigned char ninebits)
~~~~~~~~
This function is used to set up the appropriate registers
associated with the sci module. Specify the desired
baud rate. If this is possible using the current
value of Fosc, the value specified will be used - see
the PIC manual for details on baud rate selection.
If ninebits is true, 9-bit data values will be used for
both transmission and reception. The function returns
true if the desired baud rate could not be achieved;
false otherwise.
SCI_EIGHT and SCI_NINE
~~~~~~~~~ ~~~~~~~~~
These macros can beused with sci_Init() to indicate
eight- and nine-bit communication, respectively.
void
sci_PutByte(unsigned char byte)
~~~~~~~~~~~
This function is used to send an 8-bit quantity to
the SCI. The function first waits until TXIF is
set then loads the transmit register.
sci_PutNinth(bitnine)
~~~~~~~~~~~~
This macro is used to send the ninth bit to
the SCI when in nine-bit data mode. It should be
called before calling sci_PutByte().
unsigned char
sci_GetByte(void)
~~~~~~~~~~~
This function waits until the receive register is not
empty and returns the received 8-bit data.
unsigned char
sci_GetNinth(void)
~~~~~~~~~~~~
This function waits until the receive register is not
empty and returns the received ninth-bit when in nine-
bit mode. It should be called before calling
sci_GetByte()as the ninth bit is lost after calling
this function.
unsigned char
sci_GetFERR(void)
~~~~~~~~~~~
This function waits until the receive register is not
empty and returns the received frame error status bit.
It should be called before calling sci_GetByte() as
frame error information is lost after calling this
function.
unsigned char
sci_CheckOERR(void)
~~~~~~~~~~~~~
This function checks for an overrun error and resets the
receiver, by toggling the CREN bit, and returns true if
this has occured. The function returns false if no error
occured. If an overrun error occurs, the receiver is
completely disabled.
3) Examples
###########
// 8-bit mode at 9600 baud using polling
sci_Init(9600,SCI_EIGHT);
sci_PutByte(0xaa); /* send 0xaa when device is ready */
data = sci_GetByte(); /* read data when device is ready */
// 9-bit mode at 19200 baud using polling
sci_Init(19200,SCI_NINE);
sci_PutNinth(0x00); /* ninth bit is zero */
sci_PutByte(0xff); /* and data is 0xff */
if(sci_getNinth())
; /* bit nine was true */
data = sci_GetByte(); /* get 8-bit value */
if(sci_CheckOERR())
; /* an overrun error occured */
4) Using Interrupts
###################
To use interrupts with the SCI, there are several things
which must be attended to.
Firstly there must be an interrupt service routine which
can process the interrupts when they occur. There can be
only one interrupt routine associated with the PIC
processor and so this routine must be able to service
any interrupt which occurs, not just those associated
with the SCI. The following example shows an ISR which
handles reception and transmission. The RCIF, TXIF,
RCIE and TXIE bits can be used to ascertain what caused
the interrupt. In the example, if the receive register
is full (RCIF), a character is read from the SCI and
echoed back to the source. If the transmitter is
empty and the transmitter interrupts are enabled then
another byte from a message is transmitted. If all
the message has been sent, the interrupts are disabled
to prevent further transmission. If any other interrupts
are enabled, the code to handle these will also have to
appear in this ISR.
The interrupts can be enabled by setting the appropriate
bits in the INTCON register. To use the SCI, enable the
PEIE bit. If other interrupts are to be used, set the
bits corresponding to these interrupts in this register.
The global interrupt enable bit must also be set. The
TXIE and RCIE bits can then be used to mask and unmask
the interrupts at various points in your code.
sci_Init(9600, SCI_EIGHT);
PIR1 = 0; /* clear any pending interrupts */
PEIE = 1; /* enable perhipheral interrupts */
GIE = 1; /* global interrupts enabled */
/* perform other setup */
RCIE = 1; /* unmask receiver interrupts... */
/* an interrupt could now come from the SCI receiver
at any time. */
/* process data read in, if any */
RCIE = 0; /* mask receive interrupts */
/* no more interrupts can come from the receiver */
See the PIC appropriate manual for further details
on the use of PIC interrupts.
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
I want to thank you all for your kind support. I now have a wide range of solutions to try and I am sure that in the end, the USART will be defeated :) Gaston, I already use the sample code from the Hi-Tech Pic C Compiler and I have read the file sci.txt, and that code is somewhere in my code too :) For the moment, I don't dispose of the solution of connecting the PIC to the PC, and I have to make a little transmitter with max232 tomorrow (I have to buy this piece), because my schematic is to be connected to another pic, so I don't need max232. Until tomorrow, I will test the code you sent me and hope it works without having to test it with the PC.
In the meantime, I have improved the code on the keyboard side, now I can press multiple keys simultaneosly, and have each one appear only once :) Thank you again for your answers, I am learning a lot from you and I'm glad I subscribed to this list. Hope one day to know as much as you ;-)
I think I found the solution to my problem: it seems that the problem has something to do with
the direction of the pins. I was setting them to 11 (input) as I remember reading on the
datasheet. Now I've read on a program that the pins are set
movlw b'00000100' ; RB2(TX)=1 others are 0
movwf PORTB
What I'd like to know : what Tx means ? Tx is for transmission from the PIC's point of view, or from the (let's say) PC's point of view ? Or, in other words, Tx is for transmitting a byte, or for receiving it from an external device ? Cause when I set the ports like this, I receive (and print on the LCD) some garbage, but not the transmitted data. (at least it receives something :-) )
Can you make this clear for me ? :) Thank you.
I think I can answer this one for you. Tx is for PIC transmit, an output.
The pin should be set as an output, not an input. It should not really
matter however as the pin directions for both Tx and Rx are overridden by
the PIC when you enable the USART.
And ... in your code below you are not setting any port direction. You set
port direction in the TRIS register, not the PORT register.
On a further note ... I suspect you may have a RAM banking problem. If
setting PORTB below actually does set pin direction on you, then you are not
in the code page you think you are ... TRISB is in the same location one RAM
page away from PORTB. Check your RP0 and RP1 registers and make sure you
are in the RAM page you think you are.
Woops, you are using an F628 not an F877, so disregard my last email about
RAM pages. Still, my first email is still correct. You set the port
direction in the TRIS register not the PORT register.
My mistake with the PORTB code, I am initialising TRISB with 10. I managed somehow to make it receive something, but it doesn't receive the characters i send. For example:
Character sent | Character received
__________________________________
0x37 0xF3
0x39 0xCE
0x31 0xCC
0x32 0x66
Those codes are received regularly when i press the same key. Despite, the USART setup seems to be correct:
> My mistake with the PORTB code, I am initialising TRISB with 10.
> I managed somehow to make it receive something, but it doesn't
> receive the characters i send. For example:
>
> Character sent | Character received
> __________________________________
> 0x37 0xF3
> 0x39 0xCE
> 0x31 0xCC
> 0x32 0x66
Can't really see an obvious pattern, can you try sending OTHER characters,
try send 0xaa, 0x55, 0x00, 0xff, 0x0f, 0xf0, that might give us some idea of
what's wrong. You can send those codes by using the ALT key. For example, to
send 0xff=255: hold down alt, on the key pad type: 0255 and release the alt
key.
> Those codes are received regularly when i press the same key.
> Despite, the USART setup seems to be correct:
>
> SPBRG = 0x19;
> TXSTA = 0b00100100; // BRGH = 0, SYNC = 0, TXEN = 1
> RCSTA = 0b10010000; // SPEN = 1, CREN = 1
>
> PIR1 = 0; /* clear any pending interrupts */
> PEIE = 1; /* enable perhipheral interrupts */
> GIE = 1; /* global interrupts enabled */
>
> RCIE = 1;
Without knowing what BAUD rate you are sending/receiving, and what
oscillator you are using I can't tell whether what you have is correct.
> It seems to me that this hardware USART means more complicated
> code (or more complicated to write the code), instead of
> simplifying things.
Not if you read the datasheet. While it SEEMS complicated once you have it
you're set, you'll never have to "come up with it" again, and it sure saves
alot of other work. Try creating bit banged code that is oscillator
independent... it's possible, but WAY more work then using hardware UART
code and changing one constant. TTYL
Don't be disheartened. I have implemented serial comm's every way possible,
USART, SPI, I2C, and plain old bit-bashing, and believe you me the USART is
the easiest of the lot.
I would strongly suggest that you take the good advice that others have
already given you. Cut your code down to the bare minimum. Don't implement
LCD code or serial buffering or even interrupts yet as they could all be the
cause of your problems. Just use simple polled serial, and use assembly,
not the C compiler. Commmunicate with the PIC with a good terminal emulator
(i.e. NOT Hyperterminal). For a good terminal emulator that is free, I
would strongly suggest looking at Teraterm.
If however you are at your wits end, and would like a head start, email me
directly, and I will send you some working USART assembly code.
> I was setting them to 11 (input) as I remember reading on the
> datasheet. Now I've read on a program that the pins are set
>
> movlw b'00000100' ; RB2(TX)=1 others are 0
> movwf PORTB
Trust the datasheet, not random code you find on the Internet.
Quite correct, (I looked at the F628 datasheet after seeing this post) and I
do advocate following the datasheet. In fact it says the same thing in the
F877 datasheet for TRISC<7:6>. HOWEVER, in practise, this does not seem to
matter, as I have set Tx in some of my code as an output and the USART still
works absolutely correctly in both directions (and of this I am absolutely
certain). The PIC seems to be asserting the pin direction when the USART is
enabled via SPEN. Summing up, I really do not think this is the cause of
Lucian's problems.
Hello again guys (and for the last time with this problem !!) :)
Ok, so I figured out the cause of my problem : (don't curse me) it was a wiring problem, I was tying Tx to Rx and measuring with a multimeter which gave me 0 resistance, but in fact it wasn't enough for the serial communication to work. So I repaired this and the serial works without problem (polling, no I will do it with interrupts, more questions to come :) )
One note: I agree with Ian that the pin direction is not important, because they are set by the hardware. So once again, the datasheet is not so precise, because it says that they *MUST* be set in order for the USART to function.
In conclusion, it feels so good when you pass on the other side of the wall (as Ken was saying) that I don't regret having chosen to do this. Thank you all guys for your help, couldn't have done it without you (or could have done it, but in more time ;) )
More questions to come on lead-acid battery loading and stable DC source :)))
>> If you have MS Excel, why not just use the Excel spreadsheet for
>> calculating SPRIG values I submitted last week?
>
>Because then you still just end up with hard coded constants in your code,
>even if they are more likely to be right.
>
>In my opinion, the best answer is to have the assembler calculate the
>SPBRG value from the oscillator frequency and the desired baud rate. This
>is what my UART_BAUD macro does, in addition to some error checking and
>handling of different PIC UART variants. The UART_BAUD macro is available
>in STD.INS.ASPIC at http://www.embedinc.com/pic.
I would agree with Olin here. and then there is the situation where you find
you need to use a different crystal because your code is taking just that
little too long in the interrupt handler and you start to miss interrupts,
so you decide to change the crystal frequency. Changing one constant in the
source file makes all your timer and baud rate variables correct for the new
crystal (assuming you use macros for them all). Believe me once you do it
this way you will not go back.
I want to thank you all for your kind support. I now have a wide range
of solutions to try and I am sure that in the end, the USART will be
defeated :)
Gaston, I already use the sample code from the Hi-Tech Pic C Compiler
and I have read the file sci.txt, and that code is somewhere in my code
too :)
For the moment, I don't dispose of the solution of connecting the PIC to
the PC, and I have to make a little transmitter with max232 tomorrow (I
have to buy this piece), because my schematic is to be connected to
another pic, so I don't need max232.
Until tomorrow, I will test the code you sent me and hope it works
without having to test it with the PC.
In the meantime, I have improved the code on the keyboard side, now I
can press multiple keys simultaneosly, and have each one appear only
once :)
Thank you again for your answers, I am learning a lot from you and I'm
glad I subscribed to this list. Hope one day to know as much as you ;-)
Thank you, Ken, for the calculator, I tested the values with your Excel
spreadsheet and indeed the value is 25. But I think it wouldn't be such
a problem if the value is not so precise, because I think only the error
level would be greater, but the transmission would still function. Is it
correct ?
Now, having set the correct baud rate, the program still doesn't want to
function.
Please give me a hint of what is wrong. The code is:
Initialisation of USART:
unsigned char
sci_Init(unsigned long int baud, unsigned char ninebits)
{
BRGH = 1; /* high baud rate */
SPBRG = 0x19; /* set the baud rate */
I will try as Jan-Erik said to simplify the code and test it until it
runs. The led procedures are correct, because I test them at the
beginning of the program. I use procedures because I need to modify some
bits in a status byte too.
Do you guys see any mistake in this code ? Or any omission ? I am sure
that if it is, you will see it long before me ;-)
Thanks for the suggestions, now I adapted the code :)
In fact, now I put directly the value 25 in SPBRG, which is for 9600
baud rate, at 4 MHz (that's what I understood from a microchip
application note). Is this value correct for my setup ?
The TX interrupts are enabled when the send buffer has something and
disabled when empty. The code for the ISR is inspired from an example
from HT-PIC C Compiler, so I thought it is correct. If I deactivate the
flag in the main loop, is it correct ?
I tried all this, but still, it is not functioning :( It acts like it
ignores the serial part, the links are not blinking when they should
(they are supposed to blink when a byte is transmitted).
Any ideas are welcomed.
I haven't checked it with an oscilloscope because I don't have one :)
And I don't have the possibility to test it with an external device. So
my mission is pretty hard debugging the code :)
I've tested USART with polling, and a funny thing happens: after I press
two keys (and send them via USART), the console keeps resetting...why
could this happen ? the code in main is:
Sorry for the messy email message, I sent it from the webmail, and it
has
an error :( I tried to send it from Outlook, but the SMTP server is not
functional at this time :(
The code is written in C language for HiTech C Compiler, which is widely
used, so I didn't considered necessary to mention. The operations
for the initialisation of USART are basic, so the assembler code should
be
no problem, considering that other code (for LCD and keypad) compiled
successfully.
Could it be any problem if I connected Tx to Rx to test the code ? I
should get the characters sent back to Rx and from there to LCD, but
nothing
arrives.
I have a new problem with the PIC 16F628 and the hardware USART.
Although the intialisation seems to be correct, Tx is tied to Rx for
testing, when I press a key it should be transmitted and arrive back,
but the program locks (I guess because the hardware is waiting to
transmit it).
The code is the following:
unsigned char
sci_Init(unsigned long int baud, byte ninebits)
{
int X;
unsigned long tmp;
/* calculate and set baud rate register */
/* for asynchronous mode */
tmp = 16UL * baud;
X = (int)(XTAL/tmp) - 1;
if((X>255) || (X<0))
{
tmp = 64UL * baud;
X = (int)(XTAL/tmp) - 1;
if((X>255) || (X<0))
{
return 1; /* panic - baud rate
unobtainable */
}
else
BRGH = 0; /* low baud rate */
}
else
BRGH = 1; /* high baud rate */
SPBRG = X; /* set the baud rate */
SYNC = 0; /* asynchronous */
SPEN = 1; /* enable serial port pins */
CREN = 1; /* enable continuous reception */
SREN = 0; /* no effect - in asyncronous don't care*/
TXIE = 1; /* enable tx interrupts */
RCIE = 1; /* enable rx interrupts */
TX9 = ninebits?1:0; /* 8- or 9-bit transmission */
RX9 = ninebits?1:0; /* 8- or 9-bit reception */
TXEN = 0; /* enable the transmitter when data is to be
transmitted*/
return 0;
}
sci_PutByte(unsigned char bait)
{
while(!TXIF) /* set when register is empty */
continue;
TXREG = bait;
return;
}
unsigned char
sci_GetByte(void)
{
while(!RCIF) /* set when register is not empty */
continue;
Please take a look at the code and tell me what's wrong with it, because
I'm out of ideas after one day of looking for the problem.
PS: both of the pins for USART (RB1 and RB2) are inputs. Is it correct ?