|
|
View previous topic :: View next topic |
Author |
Message |
Dave_25152
Joined: 11 Dec 2010 Posts: 60
|
Problem with UART - PIC16LF1827 |
Posted: Sat Jun 23, 2012 8:44 am |
|
|
Hello all.
I am doing a very simple program and I am having some problems with it.
What happens is that when sending information for the first time, everything is fine, but the following data, it starts giving problems.
The program:
Code: | #include "16lf1827.h"
#include <stdlib.h>
#use delay (clock=1000000)
#fuses INTRC_IO, NOLVP, NOWDT, NOMCLR, NOIESO
#use RS232(baud=4800, xmit=PIN_B2,rcv=PIN_B1,PARITY=N,BITS=8,STOP=1,stream=uart)
int1 a;
unsigned int valor[4]; //4 caracteres
#INT_RDA
void serial()
{
fgets(valor, uart);
disable_interrupts(INT_RDA); //activated only after all the calculations
clear_interrupt(INT_RDA);
a=0;
}
void pic_init()
{
output_A(0);
output_B(0);
set_tris_a(0b00000000);
set_tris_b(0b00000010);
setup_adc(0);
setup_oscillator(OSC_1MHZ);
setup_timer_2(T2_DIV_BY_64,510,1);
setup_timer_4(T2_DIV_BY_64,510,1);
setup_ccp1(CCP_PWM|CCP_TIMER2);
setup_ccp2(CCP_PWM|CCP_TIMER4);
setup_uart(4800);
ENABLE_INTERRUPTS(global);
ENABLE_INTERRUPTS(INT_RDA);
}
void MAIN()
{
unsigned int16 servo1, servo2, num, veloc;
unsigned int tipo, i;
pic_init();
servo1=0;
servo2=0;
tipo=0;
set_pwm1_duty(servo1);
set_pwm2_duty(servo2);
a=1;
loop:
while(a); //wait for interrupt
printf (valor);
num=atol(valor);
tipo=num/1000;
veloc=num-(tipo*1000);
printf("\n\n\r velocidade=%Ld\n\n\r", veloc);
printf("\n\n\rtipo=%d\n\n\r", tipo);
fim_loop:
for(i=0; i<=3; i++) //colocar tudo a zero
valor[i]=0;
a=1;
output_high(pin_A6);
delay_ms(250);
output_low(pin_A6);
enable_interrupts(INT_RDA); //enable interrupt
goto loop;
} |
Surely the problem is very simple to solve, but I'm not seeing how the resolution.
Thank you. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9219 Location: Greensville,Ontario
|
|
Posted: Sat Jun 23, 2012 10:12 am |
|
|
1) always add 'errors' to the use rs232(...) line as it'll keep the hardware UART from 'locking up'.
2) delete the disable, enable interrupt code inside the ISR. The ISR actually does this for you!
3)unless you're using fast_io(), delete the set_tris_()... lines, letting the compiler automatically handle the I/O... |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sat Jun 23, 2012 10:20 am |
|
|
Quote: | unsigned int valor[4]; //4 caracteres |
You've defined valor as a 4 character array.
So what do these lines do?
Quote: | printf (valor);
num=atol(valor); |
Reduce your code to test your problem area ONLY.
Add printf lines to test intermediate values of num etc.
Do NOT use GOTO. You could define a while(1) loop instead.
Make your code more readable with indentation.
Mike |
|
|
Dave_25152
Joined: 11 Dec 2010 Posts: 60
|
|
Posted: Sat Jun 23, 2012 11:30 am |
|
|
Thanks for the replies.
I followed your suggestions, but now I have no response from the PIC.
Code: | #include "16lf1827.h"
#include <stdlib.h>
#use delay (clock=1000000)
#fuses INTRC_IO, NOLVP, NOWDT, NOMCLR, NOIESO
#use RS232(baud=4800, xmit=PIN_B2,rcv=PIN_B1,PARITY=N,BITS=8,STOP=1,stream=uart, ERRORS)
#use fast_io(A)
#use fast_io(B)
int1 a;
unsigned int valor[4]; //4 numeros
#INT_RDA
void serial()
{
clear_interrupt(int_RDA);
fgets(valor, uart);
a=0;
}
void pic_init()
{
output_A(0);
output_B(0);
set_tris_a(0b00000000);
set_tris_b(0b00000010);
setup_adc(0);
setup_oscillator(OSC_1MHZ);
setup_timer_2(T2_DIV_BY_64,510,1);
setup_timer_4(T2_DIV_BY_64,510,1);
setup_ccp1(CCP_PWM|CCP_TIMER2);
setup_ccp2(CCP_PWM|CCP_TIMER4);
setup_uart(4800);
ENABLE_INTERRUPTS(global);
ENABLE_INTERRUPTS(INT_RDA);
}
void MAIN()
{
unsigned int16 servo1, servo2, num, veloc;
unsigned int tipo, i;
pic_init();
servo1=0;
servo2=0;
tipo=0;
set_pwm1_duty(servo1);
set_pwm2_duty(servo2);
a=1;
while(1)
{
while(a); //espera pela interrupção
printf (valor);
num=atol(valor);
tipo=num/1000;
veloc=num-(tipo*1000);
printf("\n\n\r velocidade=%Ld\n\n\r", veloc);
printf("\n\n\rtipo=%d\n\n\r", tipo);
fim_loop:
for(i=0; i<=3; i++) //colocar tudo a zero
valor[i]=0;
a=1;
output_high(pin_A6);
delay_ms(150);
output_low(pin_A6);
//enable_interrupts(INT_RDA); //habilitar interrupção
}
}
|
The operation should be simple.
I send something like 2255, and in response I get "tipo = 2" and "velocidade = 255". |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jun 23, 2012 12:50 pm |
|
|
Quote: |
#use fast_io(A)
#use fast_io(B)
output_A(0);
output_B(0);
set_tris_a(0b00000000);
set_tris_b(0b00000010);
|
For this program, you don't need any of these lines. The compiler will
set the correct TRIS for you.
Quote: |
unsigned int valor[4];
num=atol(valor);
I send something like 2255,
|
atol() expects valor to be a string. A string consists of ASCII characters
and a final 0x00 byte, that marks the end of a string. Your array is not
large enough to hold the 4 digits and also the 0x00 byte. Increase
the size of the valor array.
Quote: |
#INT_RDA
void serial()
{
clear_interrupt(int_RDA);
fgets(valor, uart);
a=0;
}
void main()
{
while(a);
|
In this code, you get one RDA interrupt, and then you sit inside the
#int_RDA routine, waiting to get the string. Then you check 'a' to see
if you got it. In fact, with this program design, you don't even need
interrupts. All the code above can be replaced by the fgets() line,
if you place it in main(). Like this:
Code: |
while(1)
{
fgets(valor, uart);
printf (valor);
num=atol(valor);
|
This label doesn't do anything. Remove it. If you need a comment to
tell yourself about the code, then add a comment, not a label. |
|
|
Dave_25152
Joined: 11 Dec 2010 Posts: 60
|
|
Posted: Sat Jun 23, 2012 2:30 pm |
|
|
I'm testing a very simple program now.
But the LED flashes only 2 times .... even after I send data.
Code: | #include "16lf1827.h"
#use delay (clock=1000000)
#fuses INTRC_IO, NOLVP, NOWDT, NOMCLR, NOIESO, PUT, NOBROWNOUT
#use RS232(baud=4800, xmit=PIN_B2,rcv=PIN_B1,PARITY=N,BITS=8,stream=uart, ERRORS)
void MAIN()
{
unsigned int16 valor[4];
unsigned int i;
setup_adc(0);
setup_oscillator(OSC_1MHZ|OSC_NORMAL);
setup_uart(true);
for(i=0; i<=3; i++)
valor[i]=0;
delay_ms(500);
output_high(pin_A6);
delay_ms(150);
output_low(pin_A6);
delay_ms(150);
while(true)
{
output_high(pin_A6);
delay_ms(150);
output_low(pin_A6);
fgets(valor, uart);
delay_ms(100);
output_high(pin_A6);
delay_ms(150);
output_low(pin_A6);
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jun 23, 2012 3:17 pm |
|
|
You need to study the C language. I said to increase the size of the array.
That means increase it to:
In your case, just to be safe, you should set it to a larger number, such
as this:
Also, you are randomly inserting code that you don't understand
into the program for no reason. Remove this line. It's not needed.
The order of the top 4 lines should be like this:
Code: | #include "16lf1827.h"
#fuses INTRC_IO, NOLVP, NOWDT, NOMCLR, NOIESO, PUT, NOBROWNOUT
#use delay (clock=1000000)
#use RS232(baud=4800, xmit=PIN_B2,rcv=PIN_B1,PARITY=N,BITS=8,stream=uart, ERRORS) |
Quote: | But the LED flashes only 2 times .... even after I send data. |
You have to press the Enter key after you type the numbers into the
terminal window on your PC. Press 2255 and then press Enter.
The fgets() function looks for the Enter key to know when to end the
input session. |
|
|
Dave_25152
Joined: 11 Dec 2010 Posts: 60
|
|
Posted: Sat Jun 23, 2012 4:32 pm |
|
|
Everything works fine now.
But one problem remains. All goes well the first time. When Enio data again, the "atoll" does not work.
Code: | void MAIN()
{
unsigned int16 valor[10], num;
unsigned int i;
setup_adc(0);
setup_oscillator(OSC_1MHZ|OSC_NORMAL);
setup_uart(true);
delay_ms(500);
output_high(pin_A6);
delay_ms(150);
output_low(pin_A6);
delay_ms(150);
while(true)
{
output_high(pin_A6);
delay_ms(150);
output_low(pin_A6);
fgets(valor, uart);
delay_ms(100);
num=atol(valor);
printf (valor);
printf("valor=%Ld", num);
output_high(pin_A6);
delay_ms(150);
output_low(pin_A6);
for(i=0; i<=9; i++)
valor[i]=0;
num=0;
}
} |
|
|
|
Dave_25152
Joined: 11 Dec 2010 Posts: 60
|
|
Posted: Sat Jun 23, 2012 4:48 pm |
|
|
I do not understand why this is happening .... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jun 23, 2012 4:56 pm |
|
|
You don't read what I post. You still have the array declared as int16.
I told you to make it be int8.
Quote: | unsigned int16 valor[10],
|
I feel like quitting this thread. Someone else can help. |
|
|
Dave_25152
Joined: 11 Dec 2010 Posts: 60
|
|
Posted: Sat Jun 23, 2012 5:17 pm |
|
|
Thanks for your patience.
I changed as you told me to "int8".
The problem is not solved. |
|
|
Dave_25152
Joined: 11 Dec 2010 Posts: 60
|
|
Posted: Sat Jun 23, 2012 5:53 pm |
|
|
I have looked everywhere and nobody had a similar problem?
It's very strange, not to convert twice.
Code: | void MAIN()
{
unsigned int16 num;
unsigned int i, valor[6];
setup_adc(0);
setup_oscillator(OSC_1MHZ|OSC_NORMAL);
setup_uart(true);
delay_ms(500);
output_high(pin_A6);
delay_ms(150);
output_low(pin_A6);
delay_ms(150);
while(true)
{
output_high(pin_A6);
delay_ms(150);
output_low(pin_A6);
delay_ms(500);
fgets(valor, uart);
delay_ms(100);
num=atol(valor);
printf (valor);
printf("valor=%Ld\n\n\n\n\n", num);
output_high(pin_A6);
delay_ms(150);
output_low(pin_A6);
for(i=0; i<=5; i++)
valor[i]=0;
num=0;
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19482
|
|
Posted: Sun Jun 24, 2012 1:22 am |
|
|
There are two possible problems:
The first is time. It is not clear from your post how the data is being sent. Presumably you are typing it, or is it coming from some sort of program?.
Now, when you start, the code delays for 650mSec, before it arrives at the gets. Then waits for the string to arrive. Once it arrives, the code goes off, waits for 100mSec before doing anything else, then prints, taking perhaps 19mSec to do this - printf(valor);, is _not_ legitimate C. The correct syntax is:
printf("%s",valor);, then delays of another 150mSec, then another 650mSec, before finally returning to wait for the string. So a delay of just under 1second. If anything more than 1.9+ characters arrive in this time, these _will_ be lost, so if the transmission is automatic, or you are typing at anything more than at a crawl, the code at this point will go wrong.
Second problem, is what arrives.
Assuming this is from a PC, using a terminal program, then there is a good chance it is set to send carriage return _plus_ line feed when you hit the 'enter' key to send the value. The gets code waits for a carriage return (code 13), then returns the string. At this point, a line feed (code ten) then arrives, and when you loop round, this is still waiting to be read. The second gets, then returns:
<LF>nnnnn<\0>
and again the line feed is left waiting to be read. The string now returned begins with line feed, not a number, so atol, looks at it, and says "not a number, can't convert it".....
Change the settings in your terminal program to only send CR, not CR/LF when enter is pressed.
Best Wishes |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sun Jun 24, 2012 4:44 am |
|
|
I was thinking about helping you, and then I saw this line:A few posts higher PCM Programmer told you to get rid of it and why, but it seems like you don't want to listen to good advice. If you don't understand the advice, then say so. Ignoring good advice makes us feel like we are not being taken serious. Good, but then we have better ways to spend our time.
Another suggestion was to improve your indentation. Many passionate discussions have been held about the possible styles to choose from. I don't care which style you choose, but anything is better than your current code where you have no indentation. More info on this subject: http://en.wikipedia.org/wiki/Indent_style
Last suggestion to make you a better programmer is to take care about capitalization. The C-language is sensitive to the use of lower and UPPER capital words. The CCS compiler doesn't follow the standard and doesn't care, but this results into programs that are not portable to other compilers and more difficult to read.
For example it is good practice to write all constants in capital letters to make them stand out from the variables:
true --> TRUE
pin_A1 --> PIN_A1
but:
MAIN() --> main()
Add '#case' to the start of your program to make the compiler case sensitive. |
|
|
Dave_25152
Joined: 11 Dec 2010 Posts: 60
|
|
Posted: Sun Jun 24, 2012 7:17 am |
|
|
Thanks for the replies.
I've tried to take "setup_uart", but after the serial port no longer works.
I changed the settings on my terminal program to send only CR, but the PIC does not send any value. When I change to "CR + LF", I get data from PIC.
To send data, I'm using "uart tool" of the PICkit2.
The values are sent at intervals of 10/15 seconds.
The result is the same. Works well once and then starts sending "valor = 0".
Code: |
#CASE
void main()
{
unsigned int16 num;
unsigned int i, valor[8];
setup_adc(0);
setup_oscillator(OSC_1MHZ|OSC_NORMAL);
setup_uart(TRUE); //If I take this line, the uart port stops working ...
delay_ms(500);
output_high(PIN_A6);
delay_ms(150);
output_low(PIN_A6);
delay_ms(150);
while(TRUE)
{
output_high(PIN_A6);
delay_ms(150);
output_low(PIN_A6);
delay_ms(500);
fgets(valor);
delay_ms(1000);
num=atol(valor);
delay_ms(1000);
printf ("%s\n\n\n", valor);
printf("valor=%Ld\n\n\n\n\n", num);
output_high(PIN_A6);
delay_ms(500);
output_low(PIN_A6);
for(i=0; i<=7; i++)
valor[i]=0;
num=0;
}
}
|
I do not know what to do ...
I do not understand why everything works fine the first time and then does not work.
I've done a program like this to test: http://www.daniweb.com/software-development/cpp/threads/148373/extract-numbers-from-char
The problem is that when I write "num = valor[1]" (for example) appears in the terminal "num = 50".
Something is driving me crazy.
Thanks for your help! |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|