|
|
View previous topic :: View next topic |
Author |
Message |
lozi_dani
Joined: 22 Jan 2016 Posts: 40
|
Read characters from uart using RS232 |
Posted: Tue May 10, 2016 12:14 am |
|
|
Hi everyone!
I want to ask you about how RX/TX receives data from another device. Let me to explain:
I am using PIC18F4550 for a project where I am controlling a robot via WiFi using the ESP8266-01 module. For that WiFi communication I need to use RX and TX pins, and everything works fine with Arduino, which uses his SoftwareSerial library to make it work. In CCS we haven't that SoftwareSerial library, and I think that the way to adapt it is using #use RS232(baud,rcv..,...) instruction, am i right?
If the answer is yes, how data is received in my PIC? Using Arduino, the module sends the info as characters, and what I need to do with my Arduino is to receive all that characters, build a string with them and after search for the word I need from that string to do the movement I want. For example:
I put in the url: 192.168.x.x/motorLeftOn, where that ip address is the ip address of the Wifi module, and when I build the string, after I look for the word motorLeftOn and if I found it, then turn on the left motor. In Arduino I look for this word with an instruction like
Code: | if(...indexOf(motorLeftOn) // if I found that word in the string
Turn on left motor; |
There is something similar in CCS? How I receive the data from RX/TX in my pic? As characters too? And if this is right, with which function could I build my string and after look for that word I am interested from that string?
Thank a lot for any help you could give me!! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Tue May 10, 2016 2:27 am |
|
|
Software serial is always very restricted/problematical compared to hardware.
Think about it. To sample a serial line at 9600bps, and not miss anything, requires you (if polling), to read the line at perhaps a minimum of 3* this rate. Alternatively, you have to use edge interrupts and then measure time as well, to know what is actually going on.
You will find hundreds of threads about problems with the Arduino software serial library....
However if you are using the RX and TX pins, then you are using hardware serial, not software. Presumably using the Arduino serial library, _not_ the software serial library. You use software to talk to the UART, but it is the UART hardware that is actually handling the transmit/receive....
CCS has a software library and a hardware library. #USE RS232 if used with pins that don't have hardware serial, automatically generates software routines. However these are really best only used either for transmit only, or used on a pin which has an interrupt and then using this interrupt to trigger the receive (the RS485 examples offer this as an option). Used 'half duplex', this works quite well. The same command used with the hardware pins generates hardware serial routines.
The Arduino software library requires you to use pins that support interrupt on change.
The CCS software serial only supports half duplex operation, and unless you use an interrupt pin, requires that effectively your code is sitting 'waiting' for data to arrive.
There is a basic 9600 bps timer interrupt driven 'software serial' in the code library, which can be expanded to improve on this.
Honestly though, use the hardware pins and hardware serial.
So use the RX and TX pins on the PIC as you are doing on the Arduino.
Then CCS, is as near as anything to the original C standard. It uses getc, and putc, to get and put individual characters. Everything is based upon single characters. You can receive characters till there is a line feed (or modify the routines to use your own separator) - look at 'get_string', in the input.c include file. This receives characters up to a limited count, or a line feed, and assembles them as a 'string' in a buffer you specify. Then standard C string commands can find any particular text you want in this buffer. string.h contains the standard C string functions, so strstr, will find a target string in your buffer (be aware, returns the actual location _of_ the data, not where is is 'in' the buffer). Get a C textbook for how to use these functions. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Tue May 10, 2016 5:07 am |
|
|
I'd like to add, with regards to sending 'command data' via serial, be it wired or wireless if YOU are in control of the 'command strings' use the shortest command strings possible.
IE: instead of 'MotorLeftOn' use 'MLO'. MLO is over twice as fast to send, receive and a LOT faster in the 'parsing' function! The smaller the message the faster it goes, the quicker the PIC pogram can execute the commands.
The other 'trick' is to have all commands the same length. It simplifies the parser function,maks tables of commands and subcomands easier to read and makes for smaller programs( less memory used)
In the 'good old days' when memory was scarce,this is what we did, well we HAD to do!
Jay |
|
|
lozi_dani
Joined: 22 Jan 2016 Posts: 40
|
|
Posted: Tue May 10, 2016 5:56 am |
|
|
Thanks for the reply of both! This info help me a lot!
I am going to follow your advice temtronic. Let me show you my code Ttelmah. I think is better how i am doing it in Arduino to see better the changes:
Code: |
#include <SoftwareSerial.h>
SoftwareSerial BT1(3, 2); // RX | TX
String W =" ";
char w ;
void setup()
{
Serial.begin(9600);
BT1.begin(9600);
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
BT1.write("AT+CWMODE=3\r\n");
delay(1000);
BT1.write("AT+CIPMUX=1\r\n");
delay(1000);
BT1.write("AT+CIPSERVER=1,80\r\n");
delay(1000);
}
void loop()
{
if (BT1.available()) //WIFI -> Serial
{ w = BT1.read() ;
Serial.print(w); // building the string
W = W + w ;
}
if (Serial.available()) //Serial -> WIFI
{ char s = Serial.read();
BT1.print(s);
}
if ( w == '\n'){ // If ENTER
if ( W.indexOf("P13") > 0 ) // If P13 is in the string
{ digitalWrite( 13, !digitalRead(13)) ;
Serial.println("Invirtiendo pin 13");
}
if ( W.indexOf("P12") > 0 ) // If P12 is in the string
{ digitalWrite( 12, !digitalRead(12)) ;
Serial.println("Invirtiendo pin 12");
}
if ( W.indexOf("P11") > 0 ) // If P11 is in the string
{ digitalWrite( 11, !digitalRead(11)) ;
Serial.println("Invirtiendo pin 11");
}
W = "" ; w = ' ' ;
}
}
|
In this code, as I said, I am using SoftwareSerial library. You are right Ttelmah when you say that this library is used when I am not using hardware RX/TX because I am using pins 3 and 2 of the Arduino, which have not that function.
To adapt it to my PIC18F4550, I want to use in my PIC RX and TX pins (C7 and C6) to use the hardware serial, so I should use RS232 as: #use rs232(baud=9600 xmit=pin_c6 rcv=pin_c7), it is right?
Do not I need to use any special library of CCS to use RS232? Only with #use RS232(...) is enough?
And when receiving or transmitting data, with getc and putc I can take that characters, ok, understood until there. So what I can imagine is that there should be some way to send a string and not only a character right?I mean, if I want to send Strings, how can I use the putc function?
What I am doing in Arduino is to send via Serial, with this fragment of code:
Code: |
BT1.write("AT+CWMODE=3\r\n");
delay(1000);
BT1.write("AT+CIPMUX=1\r\n");
delay(1000);
BT1.write("AT+CIPSERVER=1,80\r\n");
delay(1000);
|
all the AT commands that my module needs to initialize the server to start the communication between the PIC and the webpage.
Here I send the whole string using the function BTI.write(); Can I do the same with some of the functions that CCS provides?
About what you said about string.h library to search a piece of a string inside a string, I am going to study this afternoon this library to see if I can get some conclusions.
Now I show the .html I built only to make more understandable how I do the communication:
Code: |
<html>
<head>
<title>Driving Motors</title>
<body>
<p <button onclick="openWinAutoMan()"><img src="imagenes/control.jpg"></button> </p>
<button onclick="openWinIzquierda()"><img src="imagenes/motor_izquierdo.jpg"></button>
<button onclick="openWinDerecha()"><img src="imagenes/motor_derecho.jpg"></button>
<script>
var myWindow;
function openWinAutoMan(){
myWindow = window.open("http://192.168.1.6/P11", "", "width=20,height=10");
Func1Delay();
}
function openWinDerecha(){
myWindow = window.open('http://192.168.1.6/P12', "", "width=20,height=10");
Func1Delay();
}
function openWinIzquierda(){
myWindow = window.open('http://192.168.1.6/P13', "", "width=20,height=10");
Func1Delay();
}
function Func1Delay() {
setTimeout(closeWin, 100);
function closeWin() {
myWindow.close()
}
}
</script>
</body>
</head>
</html>
|
Thanks for your help guys! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Tue May 10, 2016 7:32 am |
|
|
You really do need a C textbook.
The point is that CCS sticks to the original K&R commands, 99%.
In C, the command to send formatted strings, is 'printf'. It allows you to send literal strings - printf("Hello");, will send the text 'Hello' out of the current default serial port, or 'formatted' numbers/values etc.. In CCS it also allows you to route these out to different streams if required. It's a powerful command, with lots of capabilities, which a basic textbook will cover....
The CCS examples contain huge amounts of stuff showing all the things you need. For instance, look at ex_str.c This shows printing a prompt, getting a string of text from the serial, then counting the words and numbers in this. The serial I/O, and the string functions in use. There are loads of others. |
|
|
lozi_dani
Joined: 22 Jan 2016 Posts: 40
|
|
Posted: Tue May 10, 2016 9:22 am |
|
|
Thanks for your help Ttelmah!
I know C, but there are some parts of the pic that I have never used like UART, and I need to understand how it works to complete my project. Now, what I have I the Arduino receiving the commands from the web, sending 1 or 0 to some pins depending of what I am sending. And that pins are connected to a my pic. I am reading the pins of the pins using the status() function of CCS, and if that pin is receiving 1, that means that I want to turn on a specific motor. What I want is to quit the Arduino from the project and use only pic.
That is working now, I need to understand how UART works to translate that part of the code of the Arduino to my project.
I will take a look to that examples tonight. If I achieve something I will post it here. And if I have any doubt I will post it too!
Thanks a lot for guide me to find the correct info! |
|
|
lozi_dani
Joined: 22 Jan 2016 Posts: 40
|
|
Posted: Tue May 10, 2016 1:15 pm |
|
|
Ok I am working in this, and I am trying to use the function of String.H to see if I get the expected result. Correct me if I am wrong please:
Code: |
#include <UART.h>
#include <stdlib.h>
#use delay(clock=20000000)
#use RS232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7)
#define BUFFER_MAX_SIZE 16
char datos[BUFFER_MAX_SIZE];
void main()
{
//configuracion del wifi
puts("AT+CWMODE=3\r\n");
delay(1000);
puts("AT+CIPMUX=1\r\n");
delay(1000);
puts("AT+CIPSERVER=1,80\r\n");
delay(1000);
while(true){
get_string(datos, BUFFER_MAX_SIZE);
//if P1 is in datos, then motor1 = high
//else if P2 is in datos, then motor2 = high
//else if P3 is in datos, then motor1 = low and motor2 = low
}
}
|
This is the hypothetic behavior that should have the robot. I am studying how works the strstr() function, which people in the forum says that is the more recommendable function to search a string inside another string.
I am also seeing the CCS Manual to understand the functions available in the compiler, and it says that strstr returns a pointer to the occurence of the string. What I am looking for is a function which return only TRUE or FALSE when it finds a string inside another.
Is possible to adapt the response of this function to have that TRUE or FALSE? I am sorry for my unexperience with pointers.. =(
The only thing that this program should do is to receive the string and check if the command P1, P2 or P3 are in the string.
With the puts() written above, I am only sending through TX the configuration that the module never saves, so I have to configure this options each time I turn on the module. It is right to send that configuration like that or maybe I am doing something wrong?
Thanks for any help! Believe me, I am working very hard on this so don't be too bad with me please =( |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Tue May 10, 2016 1:37 pm |
|
|
Good start.
Comments inline:
Code: |
#include <UART.h>
#device PASS_STRINGS=IN_RAM
//This may need to be inside UART.h. Depends what this contains
//This is needed to allow the PIC to handle strings in ROM like strings
//in RAM
#use delay(clock=20000000)
//We don't know that this is right, depends on your chip, and do
//you have a 20MHz crystal attached?.
#use RS232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7, ERRORS)
//When using the hardware UART, always use ERRORS. Otherwise if
//a couple of characters get missed, the UART [u]will[/u] hang.
//Always do the delay, and UART setup's before including anything
//other than processor setup stuff
#include <input.h> //contains get_string
#include <stdlib.h>
#include <string.h> //needed for the string functions.
#define BUFFER_MAX_SIZE 16
char datos[BUFFER_MAX_SIZE];
int8 dummy;
#define CLEAR_UART() while(kbhit()) dummy=getc()
void main(void)
{
delay_ms(500);
//PIC's wake up very quickly. May be too fast for your modem
//better to leave a little delay.
//configuracion del wifi
puts("AT+CWMODE=3\r\n");
//At this point the modem _will_ send a reply. If you don't read this
//without ERRORS this will hang the UART.
delay_ms(1000); //CCS allows you to delay in mSec or uSec
CLEAR_UART(); //throw reply away
puts("AT+CIPMUX=1\r\n");
delay_ms(1000); //as above
CLEAR_UART();
puts("AT+CIPSERVER=1,80\r\n");
//You now want to get the reply, delaying will miss this....
while(true){
get_string(datos, BUFFER_MAX_SIZE);
if (strstr(datos,"P1")!=NULL)
{
//here "P1" was in the string
}
//if P1 is in datos, then motor1 = high
//else if P2 is in datos, then motor2 = high
//else if P3 is in datos, then motor1 = low and motor2 = low
}
}
|
This assumes your control strings do end with a line feed (get_string requires this) |
|
|
lozi_dani
Joined: 22 Jan 2016 Posts: 40
|
|
Posted: Tue May 10, 2016 1:51 pm |
|
|
Many many thanks Ttelmah!
I am going to try it now! But let me ask you a little stupid thing, The puts() function is right in my code? I mean, that function, in the same way I have it in my code, is working good?
Now, while i am trying to understand how get_string() and puts() works, I have tried to do this:
Code: |
#include <18F4550.h>
#include <stdlib.h>
#use delay(clock=20000000)
#use RS232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7)
#define BUFFER_MAX_SIZE 16
char datos[BUFFER_MAX_SIZE];
void main()
{
//configuracion del wifi
puts("AT+CWMODE=3\r\n");
delay_ms(1000);
puts("AT+CIPMUX=1\r\n");
delay_ms(1000);
puts("AT+CIPSERVER=1,80\r\n");
delay_ms(1000);
while(true){
//get_string(datos, BUFFER_MAX_SIZE);
puts("sending data to web");
delay_ms(1000);
}
}
|
Only i am trying to see in the IP address of my wiFi module each 1 second the string "sending data to web". This should works?
About the clock, I have a 20MHz crystal and I've configured the fuses as Divided by 5 to have the 20MHz of the external clock hehe, I forget to specify that.
This part
Code: |
if (strstr(datos,"P1")!=NULL)
|
Is very important to me. As I can understand, if it is != NULL, that means that there is a match. I don't care where is placed in the string and nothing like that, only to know if there is a match, and with this now I understand how I can get it! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Tue May 10, 2016 1:57 pm |
|
|
If you have it divided by 5, then your clock rate will be 4MHz.
Tell us what your chip actually is, and show your fuses.
Clock needs to match what is actually being used inside the chip, or nothing serial will work.
You can use puts, or printf. Printf allows you to include values that change (variables). Hence it is much more common to use this. Both will work. |
|
|
lozi_dani
Joined: 22 Jan 2016 Posts: 40
|
|
Posted: Tue May 10, 2016 2:04 pm |
|
|
Sorry, I am wrong, I wrote too fast. I am using external clock, so I am using HS fuse to use it. my pic is 18F4550.
I am trying this now:
Code: |
#include <UART.h>
#include <input.h> //contains get_string
#include <string.h> //needed for the string functions.
#include <stdlib.h>
#use delay(clock=20000000)
#use RS232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7, ERRORS)
int8 dummy;
#define CLEAR_UART() while(kbhit()) dummy=getc()
#define BUFFER_MAX_SIZE 16
char datos[BUFFER_MAX_SIZE];
#define CLEAR_UART() while(kbhit()) dummy=getc()
void main()
{
delay_ms(500);
//configuracion del wifi
puts("AT+CWMODE=3\r\n");
delay_ms(1000);
CLEAR_UART(); //throw reply away
puts("AT+CIPMUX=1\r\n");
delay_ms(1000);
CLEAR_UART(); //throw reply away
puts("AT+CIPSERVER=1,80\r\n");
while(true){
//get_string(datos, BUFFER_MAX_SIZE);
puts("enviando datos a web");
delay_ms(1000);
}
}
|
But I get the error: input.h file can not be opened. I am looking for this library but I haven't in my drivers. Maybe I have to download it from somewhere?
edit: Sorry, I've notice that I have a file called input.c, and I've also seen that there are few examples where people use #include <input.c> instead of #include <input.h>
I am going to try when I arrive at home this afternoon because i am at work now, but when i've tried I will put the results.
In the meantime, you know Ttelmah if when you refer to input.h, you want to say input.c? I've been looking the code of input.c file and it has a get_string() function:
Code: |
void get_string(char* s, unsigned int8 max) {
unsigned int8 len;
char c;
--max;
len=0;
do {
c=getc();
if(c==8) { // Backspace
if(len>0) {
len--;
putc(c);
putc(' ');
putc(c);
}
} else if ((c>=' ')&&(c<='~'))
if(len<=max) {
s[len++]=c;
putc(c);
}
} while(c!=13);
s[len]=0;
}
|
Is this the function I need to be able to run my code? I guess it is, but only to confirm. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Wed May 11, 2016 12:54 am |
|
|
They call it input.c
It's a bit of an 'annoyance', that for some completely unknown reason, they call a lot of their include files .c, rather than .h..... |
|
|
lozi_dani
Joined: 22 Jan 2016 Posts: 40
|
|
Posted: Wed May 11, 2016 4:30 pm |
|
|
Ok now I am trying this simple example only to see if my PIC send something to the url of the wifi module:
Code: |
#include <UART.h>
#include <input.c> //contains get_string
#include <string.h> //needed for the string functions.
#include <stdlib.h>
#use delay(clock=20000000)
#use RS232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7, ERRORS)
int8 dummy;
#define CLEAR_UART() while(kbhit()) dummy=getc()
//#define BUFFER_MAX_SIZE 16
//char datos[BUFFER_MAX_SIZE];
void main()
{
delay_ms(500);
//configuracion del wifi
puts("AT+CWMODE=3\r\n");
delay_ms(1000);
CLEAR_UART(); //throw reply away
puts("AT+CIPMUX=1\r\n");
delay_ms(1000);
CLEAR_UART(); //throw reply away
puts("AT+CIPSERVER=1,80\r\n");
while(true){
//get_string(datos, BUFFER_MAX_SIZE);
puts("enviando datos a web");
delay_ms(1000);
}
}
|
But it isn't works. Maybe is something wrong in my code?
My wifi module, the ESP8266-01, has a little blue led which shows me if something is sending or receiving through the TX/RX pins. I can see how each second the blue led blinks as if something is sended or received, so I understand that there is some information going through the UART, but when I put in the browser the IP address, I am not able to see anything. The web says that it cannot open the page, as if nothing was connected there. I've done a ping using the CMD and that IP address sends me a response, so i guess that the module is active.
Maybe could I am doing something wrong in the code? Or maybe should I check other things to see why is not working?
Thanks a lot! |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Wed May 11, 2016 5:18 pm |
|
|
this line
can hang the execution waiting for a character if none has arrived. it is a primary reason you should not use get_string() if you want a reliable program. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Wed May 11, 2016 6:03 pm |
|
|
There is another 'workaround' for a PIC 'hanging' forever waiting for a string to come...
CCS has an example of a 'timed' input where either the string IS received OR a 'timeout' has occurred. This 'timeout' generally is 2X the time it takes for the PIC to normally receive the string.
I think this example is in the FAQ section of the manual...
Jay |
|
|
|
|
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
|