// PIC16F628A Configuration Bit Settings
// 'C' source line config statements
#include <xc.h>
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
// CONFIG
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = ON // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = ON // Low-Voltage Programming Enable bit (RB4/PGM pin has PGM function, low-voltage programming enabled)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
Serial communication library for PIC16F series MCUs.
Compiler: Microchip XC8 v1.12 (http://www.microchip.com/xc)
Version: 1.0 (21 July 2013)
MCU: PIC16F877A
Frequency: 4MHz
NOTICE
NO PART OF THIS WORK CAN BE COPIED, DISTRIBUTED OR PUBLISHED WITHOUT A
WRITTEN PERMISSION FROM EXTREME ELECTRONICS INDIA. THE LIBRARY, NOR ANY PART
OF IT CAN BE USED IN COMMERCIAL APPLICATIONS. IT IS INTENDED TO BE USED FOR
HOBBY, LEARNING AND EDUCATIONAL PURPOSE ONLY. IF YOU WANT TO USE THEM IN
COMMERCIAL APPLICATION PLEASE WRITE TO THE AUTHOR.
WRITTEN BY:
AVINASH GUPTA
me@avinashgupta.com
*******************************************************************************/
#include <stdint.h>
#include <xc.h>
#include "usart_pic16.h"
void USARTInit(uint16_t baud_rate)
{
//Setup queue
UQFront=UQEnd=-1;
//SPBRG
switch(baud_rate)
{
case 9600:
SPBRG=25; //datasheets pagina 76 pic16f628
break;
case 19200:
SPBRG=12;
break;
case 28800:
SPBRG=42;
break;
case 33600:
SPBRG=36;
break;
}
//TXSTA
TXSTAbits.CSRC=1;
TXSTAbits.TX9=0; //8 bit ttsransmission
TXSTAbits.TXEN=1; //Transmit enable
TXSTAbits.SYNC=0; //Async mode
TXSTAbits.BRGH=1; //High speed baud rate
//RCSTA
RCSTAbits.SPEN=1; //Serial port enabled
RCSTAbits.RX9=0; //8 bit mode
RCSTAbits.CREN=1; //Enable receive
RCSTAbits.ADDEN=0; //Disable address detection
//Receive interrupt
RCIE=1;
PEIE=1;
ei();
}
void USARTWriteChar(char ch)
{
while(!PIR1bits.TXIF);
TXREG=ch;
}
void USARTWriteString(const char *str)
{
while(*str!='\0')
{
USARTWriteChar(*str);
str++;
}
}
void USARTWriteLine(const char *str)
{
USARTWriteChar('\r');//CR
USARTWriteChar('\n');//LF
USARTWriteString(str);
}
void USARTHandleRxInt()
{
if(RB1==1)
RB1=0;
else
RB1=1;
//Read the data
char data=RCREG;
//Now add it to q
if(((UQEnd==RECEIVE_BUFF_SIZE-1) && UQFront==0) || ((UQEnd+1)==UQFront))
{
//Q Full
UQFront++;
if(UQFront==RECEIVE_BUFF_SIZE) UQFront=0;
}
if(UQEnd==RECEIVE_BUFF_SIZE-1)
UQEnd=0;
else
UQEnd++;
URBuff[UQEnd]=data;
if(UQFront==-1) UQFront=0;
}
char USARTReadData()
{
char data;
//Check if q is empty
if(UQFront==-1)
return 0;
data=URBuff[UQFront];
if(UQFront==UQEnd)
{
//If single data is left
//So empty q
UQFront=UQEnd=-1;
}
else
{
UQFront++;
if(UQFront==RECEIVE_BUFF_SIZE)
UQFront=0;
}
return data;
}
uint8_t USARTDataAvailable()
{
if(UQFront==-1) return 0;
if(UQFront<UQEnd)
return(UQEnd-UQFront+1);
else if(UQFront>UQEnd)
return (RECEIVE_BUFF_SIZE-UQFront+UQEnd+1);
else
return 1;
}
void USARTWriteInt(int16_t val, int8_t field_length)
{
char str[5]={0,0,0,0,0};
int8_t i=4,j=0;
//Handle negative integers
if(val<0)
{
USARTWriteChar('-'); //Write Negative sign
val=val*-1; //convert to positive
}
else
{
USARTWriteChar(' ');
}
if(val==0 && field_length<1)
{
USARTWriteChar('0');
return;
}
while(val)
{
str[i]=val%10;
val=val/10;
i--;
}
if(field_length==-1)
while(str[j]==0) j++;
else
j=5-field_length;
for(i=j;i<5;i++)
{
USARTWriteChar('0'+str[i]);
}
}
void USARTGotoNewLine()
{
USARTWriteChar('\r');//CR
USARTWriteChar('\n');//LF
}
void USARTReadBuffer(char *buff,uint16_t len)
{
uint16_t i;
for(i=0;i<len;i++)
{
buff[i]=USARTReadData();
}
}
void USARTFlushBuffer()
{
while(USARTDataAvailable()>0)
{
USARTReadData();
}
}/******************************************************************************
Serial communication library for PIC16F series MCUs.
Compiler: Microchip XC8 v1.12 (http://www.microchip.com/xc)
MCU: PIC16F877A
Frequency: 4MHz
NOTICE
NO PART OF THIS WORK CAN BE COPIED, DISTRIBUTED OR PUBLISHED WITHOUT A
WRITTEN PERMISSION FROM EXTREME ELECTRONICS INDIA. THE LIBRARY, NOR ANY PART
OF IT CAN BE USED IN COMMERCIAL APPLICATIONS. IT IS INTENDED TO BE USED FOR
HOBBY, LEARNING AND EDUCATIONAL PURPOSE ONLY. IF YOU WANT TO USE THEM IN
COMMERCIAL APPLICATION PLEASE WRITE TO THE AUTHOR.
WRITTEN BY:
AVINASH GUPTA
me@avinashgupta.com
*******************************************************************************/
#ifndef USART_PIC16_H
#define USART_PIC16_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
//Constants
#define RECEIVE_BUFF_SIZE 64
//Varriables
volatile char URBuff[RECEIVE_BUFF_SIZE]; //USART Receive Buffer
volatile int8_t UQFront;
volatile int8_t UQEnd;
void USARTInit(uint16_t baud_rate);
void USARTWriteChar(char ch);
void USARTWriteString(const char *str);
void USARTWriteLine(const char *str);
void USARTWriteInt(int16_t val, int8_t field_length);
void USARTHandleRxInt();
char USARTReadData();
uint8_t USARTDataAvailable();
void USARTGotoNewLine();
void USARTReadBuffer(char *buff,uint16_t len);
void USARTFlushBuffer();
#ifdef __cplusplus
}
#endif
#endif /* USART_PIC16_H */
#include <stdint.h>
#include <xc.h>
#include "usart_pic16.h"
void interrupt ISR(void)
{
if (RCIE && RCIF) {
USARTHandleRxInt();
return;
}
}#define _XTAL_FREQ 4000000
#include <xc.h>
#include <pic16f628a.h>
#include <stdio.h>
#include <stdlib.h>
#include "confbits.h"
#include "lcd.h"
#include "usart_pic16.h"
/* defino headers */
#define boton PORTBbits.RB4
//************************** defino funciones main *************************
void lcdout (int x , int y , char *b);
void led (void);
void init (void);
void web (void);
char data ;
unsigned char teclado (void);
//**************************************************************************
unsigned char resultado = 0;
void main(void)
{
init (); // inicializo el up
Lcd_Init();
Lcd_Clear();
lcdout(4,1,"Programa"); // escribo lcd con datos de copyrights
lcdout(2,2,"Copyrights 2015");
USARTInit(9600);
while(1)
{
// if (teclado() == 1)
{
//led(); // prendo y apago led
// web(); //transmito los datos al esp8266
uint8_t n= USARTDataAvailable();
//si tengo datos
if(n!=0)
{
//leo el serie
char data=USARTReadData();
Lcd_Clear();
lcdout(1,1,data); // recibo repuesta de esp8266
}
}
}
}
// ******************** inicializacion cpu ***************************
void init (void)
{
PCONbits.OSCF ;// reloj en 4 mhz
CMCON = 0X07 ; //apaga los comparadores y habilita los pines de I/O
TRISA = 0x00;
PORTA = 0X00;
TRISBbits.TRISB3 = 0; // led como salida
TRISBbits.TRISB4 = 1; // boton como entrada
TRISBbits.TRISB1 = 1; //terminal rx como entrada
TRISBbits.TRISB2 = 1;
}
void interrupt ISR(void)
{
if (RCIE && RCIF) {
USARTHandleRxInt();
return;
}
}void USARTHandleRxInt()
{
if(RB1==1)
RB1=0;
else
RB1=1;
//Read the data
char data=RCREG;
//Now add it to q
if(((UQEnd==RECEIVE_BUFF_SIZE-1) && UQFront==0) || ((UQEnd+1)==UQFront))
{
//Q Full
UQFront++;
if(UQFront==RECEIVE_BUFF_SIZE) UQFront=0;
}
if(UQEnd==RECEIVE_BUFF_SIZE-1)
UQEnd=0;
else
UQEnd++;
URBuff[UQEnd]=data;
if(UQFront==-1) UQFront=0;
}uint8_t n= USARTDataAvailable();
//si tengo datos
if(n!=0)
{
//leo el serie
char data=USARTReadData();
Lcd_Clear();
lcdout(1,1,data); // recibo repuesta de esp8266
}USARTInit(9600);
RCIE=0;No soy para nada experto pero tratare de ayudarte.
creo qe el error es que estas leyendo el dato en la rutina del main, pero tambien estas recibiendo el dato en la rutina de interrupcion:
Para RodrigoAndres
Para mi que estas equivocado Rodrigo, al menos de lo que lei del codigo.
USARTHandleRxInt() lo que hace esa funcion es guardar el dato en el buffer que crea el archivo USART_PIC16.H
Esa variable se llama URBuff[] y de tamaño RECEIVE_BUFF_SIZE
Usa dos indices : UQEnd y UQFront, el primero indica la posicion del ultimo valor que llego al buffer, y el otro indica la posicion del caracter que va a ser leido , ejemplo recibi 10 caracteres y lei solo 3, UQFront=2 y UQEnd=9 (recorda que incluye el 0)
Basciamente crea un array y lo va llenando.
Las demas funciones:
USARTDataAvailable()
Simplemente ve si hay un dato en el buffer ese craedo, devuelve 0 si no hay nada o un valor que es el tamaño del buffer
USARTReadData()
Devuelve el dato recibido
Al menos las funciones esas parecen estar bien.,
Para Rseliman
Lo que si le quitaria es el return a la funcion de interrupcion, es decir:Código: C
void interrupt ISR(void) { if (RCIE && RCIF) { USARTHandleRxInt(); } }
Ademas en tu codigo, segun como estas haciendo el main, estaria enviando al 1,1 todas letras asi que irian apareciendo letra por letra lo que le estas enviando.
es decir si mandas "HOLA" imagino que verias solo la "A" en la posicion 1,1 del LCD.
La unica que te queda para probar si es esto, es que mandes 1 por 1 despacio los datos. Asi podes verlo.
Si aun asi despues de todo esto NO te funciona ya miraria la configuracion del UART.
Si quisieras recibir todo junto ya deberias modificar el codigo, usar otras funciones y por ahi hasta modificar algunas como la de la interrupcion.
.y a veces me muestra codigo que esta escrito al final del programaEsto no deberia pasar ni queriendo, ya que seria un poco imposible, en las PC "si se puede" por que los datos/instrucciones (Von Neumann) estan juntos y ante un buffer/stack overflow podria ocurrir que se libere informacion que no se deba. Pero aca esta limitado los limites de los punteros del buffer. Y es una arquitectura diferente ( Hardvard ).
Hay 3 cosas que me preocupan.. Como dije las funciones de la libreria parecen funcionar perfectamente, no las use pero siguiendo la logica del programa parece que si funciona.
1 - es el main. Hay llaves por demas {} , imagino que son del if, pero veo que no las comentaste. No se ni como es que compilo eso.
2 - la funcion lcdout() segun como este programado puede fallar , por lo que parece envia un string, y normalmente un string en C es una coleccion de char + un caracter nulo , es decir '\0'. Ese caracter nulo se usa para saber cuando termina el string, con lo cual aca:
lcdout(4,1,"Programa");
Funcionaria ya que "Programa" en realidad es array[9]={'P','r','o','g','r','a','m','a','\0'} y estarias apuntando a la P al comienzo, es decir se le envia la direccion de comienzo. Por que es mas facil hacerlo con punteros
Mientras que cuando vos usas
lcdout(1,1,data);
ocurren 2 cosas que pueden hacer que falle lo que vos queres hacer, envias el contenido y por otro lado envias un solo caracter.
Asi que aca podes probar otra cosa
Si lcdout() acepta 1 solo caracter sin el caracter nulo entonces:Código: C
lcdour(1,1,&data);
Si lcdout() NO acepta sin el caracter nulo, es decir espera un string, podes hacer algo asi para intentar remediarloCódigo: C
while(1) { //si tengo datos if(USARTDataAvailable()) { char data[2]; data[0]=USARTReadData(); data[1]='\0' Lcd_Clear(); lcdout(1,1,data); // recibo repuesta de esp8266 } }
3 - tamaño del buffer, en el .h esta definido en 64, lo cual estas ocupando 64 espacios de memoria sin sentido, achicalo a 10/15 , eso va a depender que rapido estes leyendo los datos guardados, a no ser que tengas que recibir los 64 datos para asi luego trabajar.Citar.y a veces me muestra codigo que esta escrito al final del programaEsto no deberia pasar ni queriendo, ya que seria un poco imposible, en las PC "si se puede" por que los datos/instrucciones (Von Neumann) estan juntos y ante un buffer/stack overflow podria ocurrir que se libere informacion que no se deba. Pero aca esta limitado los limites de los punteros del buffer. Y es una arquitectura diferente ( Hardvard ).
Si esta sucediendo me parece mas un problema del simulador/debugger si es que estas usando... Ademas los 16F no poseen memoria lineal y creo que tampoco tienen acceso como datos la memoria flash, aparte de todo esto, el programa en C no es lo que se guarda en el micro, ni tampoco en ASM ya que estos son nemonicos y lo que se guarda son los OPcodes que no tienen ninguna relacion con las letras ni de ASM, ni de C. Asi que aun lo veo muchisimo mas improbable que sea un problema del micro.
Lo que si puede estar mostrando basura por redireccionarlo a otro lado. Y hasta no encontrar un caracter nulo agarrar todos los datos posibles ( de la memoria de datos ) y mostrarlos en el LCD
lo que si no pude entender es porque me imprimia parte del codigo ...la verdad no se , lo hacia en Proteus y en el protoboard tambien ....
Ahora veo las palabras completas , solo que de a una letra por ves ...y tengo que detectar un OK que viene del esp8266 placa wifi ....ya vere como lo resuelvo ...
si es verdad el tiene razon con eso, pero es muy raro qe funcione sin qe borres la bandera de interrupcion RCIF, como ases para que funcione asi??
RCIF: EUSART Receive Interrupt Flag bity
1 = The EUSART receive buffer is full (cleared by reading RCREG)
The RCIF interrupt flag bit is read-only, it cannot be set or cleared by software.Yo tambien por ahi me olvido de esto xD.
Era parte del codigo , pero claro otra ves tenes razon ...eran caracteres asschi , ya que estaban entre comillas , uso el esp8266 para enviar datos a una pagina web ..y lo que se veia eran los datos que direccion web ...de todas maneras es raro , pero bueno ...desp te voy a preguntar de nuevo por el tema de reconocer el OK que me devuelve el 8266 ...yo le transmito comandos AT ..y el me contesta con OK ...pero en el ultimo caso tengo que detectar la respuesta de la pagina ..que es un numero de 3 cifras ...el tema es que viene con mucho texto ...lo que hago es un GET a un PHP ...a una base de datos y cuando me contesta tengo que tomar ese numero ...lo que si no pude entender es porque me imprimia parte del codigo ...la verdad no se , lo hacia en Proteus y en el protoboard tambien ....
Estas seguro que era parte del codigo o solo eran los datos ?, por ejemplo "Copyrights 2015" o "Programa" , etcAhora veo las palabras completas , solo que de a una letra por ves ...y tengo que detectar un OK que viene del esp8266 placa wifi ....ya vere como lo resuelvo ...
HTTP/1.x 200 OK
Transfer-Encoding: chunked
Date: Sat, 28 Nov 2009 04:36:25 GMT
Server: LiteSpeed
Connection: close
X-Powered-By: W3 Total Cache/0.8
Pragma: public
Expires: Sat, 28 Nov 2009 05:36:25 GMT
Etag: "pub1259380237;gz"
Cache-Control: max-age=3600, public
Content-Type: text/html; charset=UTF-8
Last-Modified: Sat, 28 Nov 2009 03:50:37 GMT
X-Pingback: http://net.tutsplus.com/xmlrpc.php
Content-Encoding: gzip
Vary: Accept-Encoding, Cookie, User-Agent
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Top 20+ MySQL Best Practices - Nettuts+</title>
<!-- ... rest of the html ... -->
void respuesta(void)
{
while(1)
{
//Get the amount of data waiting in USART queue
uint8_t n= USARTDataAvailable();
char data[];
//If we have some data
if(n!=0)
{
//Read it)
USARTReadBuffer(&data,n);
sprintf(salida,"%s",&data);
Lcd_Clear();
Lcd_Set_Cursor(2,1);
Lcd_Write_String(salida);
}
}
}Hola Rseliman.
Cambia esto: char conect[11] por esto char conect[12]
Y nos comentas.
Otra cosa prueba el programa paso a paso en el proteus si lo tienes a mano. :mrgreen:
Saludos
Veamos, si estas enviando solo los siguentes caracteres: "(CONECTADO)", al realizar la comparacion deberia funcionarte bien, pero si envias otros caracteres distintos alli abra problemas.
Lo estas probando en fisico o con el simulador?
Y el compilador que estas utilizando es el XC8?
Saludos
+IPD,175:HTTP/1.1 200 OK
Server: nginx
Date: Sat, 26 Sep 2015 14:03:28 GMT
Content-Type: text/html
Connection: close
X-Powered-By: PHP/5.3.29
X-Proxy-Cache: BYPASS
(CONECTADO)CLOSED if (cone[a] == data)
{
conect[a] = data ;
a++ ;
} if (cone[a] == data)
{
conect[a] = data ;
a++ ;
}
if (a==11)
{
// Encontre la palabra
conect[a] = '\0';
a=0; // Asi no molesta y esta listo a recibir otra ves
Lcd_Write_String("conect");
}No me gusta la forma de obtener el dato. Realmente tenes un "(CONECTADO)" ? Y siempre es asi ?
Si tengo siempre un (CONECTADO) , simpre que tenga internet ,,y que el esp8266 logre conectarse antes de esto
Yo pense que era una respuesta de HTTP, y si la palabra que buscabas estaba ubicada en el lugar que decis te indicaba desde donde tenias que tomar los datos.Código: [Seleccionar]+IPD,175:HTTP/1.1 200 OK
Server: nginx
Date: Sat, 26 Sep 2015 14:03:28 GMT
Content-Type: text/html
Connection: close
X-Powered-By: PHP/5.3.29
X-Proxy-Cache: BYPASS
(CONECTADO)CLOSED
Si si asi es esa es la pagina que me tira el conectado , la cual es propia y esta escrita en PHP por mi
Como que primero debes SI o SI saber si la respuesta fue correcta por lo cual analizar y encontrar el 200 al comienzo ( 1era linea ) es fundamental, luego analizas la respuesta de la pagina que creo que es ese "(CONECTADO)" que esperas.
el tema es que el (CONECTADO) aparece porque vailda datos en una base de datos ...o sea que el 200 podria aparecer igual y no asi el conectado ...por eso me aseguro que esta todo bien si tengo el conectado ...
Si es una pagina tuya entonces ni te compliques ponerle parentesis ya que son 2 caracteres mas a comparar, a no ser que quieras asegurarte. Sabes que la respuesta del HTTP, viene seguido de un doble salto y sabes CUAL es la respuesta si o si del HTTP.
Entonces:
- Para obtener el codigo de respuesta, tenes que parsear la primera linea, una maquina de estado que lo haga y listo. que guarde el string de la primer linea ( hasta el \n ) Luego podes buscar los 2 espacios en blancos " " y lo que esta entre medio de eso es.. tu codigo de respuesta. Te aseguras que sea 200.
- Finalmente seguis recibiendo, si era 200 te va a importar obviamente, sino omitis todo no guardas nada y das aviso que un problema ocurrio , de tener un 200 cuando detectas un doble salto, comenzas nuevamente a guardar la linea. Aca Creo que hay 2 opciones:
Si es tu codigo (el del PHP), sabes exactamente la respuesta que te va a dar, lo cual podes tratar de encontrar el "(CONECTADO)" Ya que va a tener la respuesta exacta a tu codigo .
Si no es tu codigo ( el de PHP), podes restringir a que guarde solo algunos caracteres ( digamos unos 15 ) o hasta que encuentre un nuevo salto de linea. Y nuevamente comparar.
Al menos es lo que haria yo. Me aseguro de una falla de conexcion, de cualquier otra respuesta del servidor buscando el 200, y luego busco la respuesta, que se que va a comenzar luego del doble salto.
Con respecto a tu codigo:
char cone[] = "(CONECTADO)"; Eso, en realidad es esto '(','C','O','N','E','C','T','A','D','O',')','\0' (son 12, no 11)
si si de acuerdo con eto me comi el \0
En una respuesta asi:
(CONECTADO)CLOSED
Y no tenes ese caracter nulo, Entonces veamos por parte:Código: [Seleccionar]if (cone[a] == data)
{
conect[a] = data ;
a++ ;
}
hacer eso, si a termina siendo 11 al final del if, indica que realmente la palabra esta ahi, y no volver a "chequear" con el strcmp, es redundante.
Por otra parte tu codigo no distinguiria de esto:
a(ewqClalaOewqNerrEtgCdTasAetDyhOm)eC3L123O5SasEgDwq
Lo cual nuevamente no es correcto :P.
Y otro problema MAS!
Una ves que "a" supera 10 que es el limite del array "conect" estarias ESCRIBIENDO las posiciones de memoria siguientes que tal ves responden a data u otra variable, o tal ves por suerte no exista nada alli
Me explico, si tenes los datos asi en memoria:
conect[0] -- a = 0
conect[1]
....
conect[10] -- a = 10
otra variable -- a = 11
Sabra dios que hay aca -- a = 12 y asi... ( Lo cual NUNCA termina! )
habia contemplado el que no se pase de 11 y se lo saque pero si me doy cuenta de lo que pasa ...muchas gracias !!!
Para C terminar una string necesita un 0x00, asi que va a continuar grabando hacia abajo hasta que "a" tenga un overflow o dejes de meterle datos, y cuando vos haces un printf, va a enviar todos los valores hasta que encuentre el primer 0x00 ( '\0' )
Entonces Podes hacer una cosa simple y tenerlo funcionando pero no evita los errores anteriores:
Reformar a conect haciendolo de 12 lugares
char conect[12];
Y luego el codigo:Código: [Seleccionar]if (cone[a] == data)
{
conect[a] = data ;
a++ ;
}
if (a==11)
{
// Encontre la palabra
conect[a] = '\0';
a=0; // Asi no molesta y esta listo a recibir otra ves
Lcd_Write_String("conect");
}
Nuevamente te repito, esto NO evita otros problemas que puedas tener y que nombre antes. Solamente es un "fix" a tu programa.
PD: 3 respuestas mientras que escribi esto e.e