Autor Tema: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS232  (Leído 25848 veces)

0 Usuarios y 3 Visitantes están viendo este tema.

Desconectado edu1989

  • PIC18
  • ****
  • Mensajes: 275
Hola amigos. Me dispongo a realizar un programita que tiene el objetivo de enviar datos de un sensor de temperatura( TC77) y un potenciometro por el puerto serie.
Quiero que el PIC este en un modo Sleep hasta que:

- Un cliente envie un comando o un caracter, y se envien los dos datos ( esquema Cliente- Servidor)
- Pase algo extraño con alguno de los dos valores. (p.ej: enviar la temperatura cuando baje de 18ºC o enviar el valor del potenciometro cuando supere una cierta barrera)

Tengo diversas dudas :

- He visto en el datasheet de toda mi placa( PICDEM FS USB Demo Board Users Guide 51526a) que para transmitir los datos del sensor tengo que usar el modulo SPI( Serial Peripheral Interface. En la pag 193 del datasheet sale como hay que configurarlo. Básicamente hay cuatro pines a tener en cuenta: Serial data out       ( RC7), Serial Data in(RB0), Serial Clock (RB1) y Slave select (RA5).
Para enviar los datos del potenciometro uso también el modulo SPI? ( no se si se puede considerar el potenciometro como periférico). Como leo y envió los datos del potenciometro?
Si la respuesta es que si, las funcionen para enviar, recibir etc... me imagino que tengo que sacarlas de la librería spi de Hi-tech picc18 verdad?

- Por otro lado, tengo que configurar el PIC en " Sleep Mode" hasta que suceda alguna interrupción?



De momento son las dudas que me surgen. Ya he leído la información del datasheet tanto del mudo EUSART como del modulo SPI.Ahora voy a hacer una primera versión del programa a ver que dudas mas me salen.

Muchas gracias a todos de antemano.

            
« Última modificación: 30 de Noviembre de 2010, 08:38:20 por edu1989 »

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS232
« Respuesta #1 en: 30 de Noviembre de 2010, 10:34:46 »
Hola amigos. Me dispongo a realizar un programita que tiene el objetivo de enviar datos de un sensor de temperatura( TC77) y un potenciometro por el puerto serie.
Quiero que el PIC este en un modo Sleep hasta que:

- Un cliente envie un comando o un caracter, y se envien los dos datos ( esquema Cliente- Servidor)
- Pase algo extraño con alguno de los dos valores. (p.ej: enviar la temperatura cuando baje de 18ºC o enviar el valor del potenciometro cuando supere una cierta barrera)

Tengo diversas dudas :

- He visto en el datasheet de toda mi placa( PICDEM FS USB Demo Board Users Guide 51526a) que para transmitir los datos del sensor tengo que usar el modulo SPI( Serial Peripheral Interface. En la pag 193 del datasheet sale como hay que configurarlo. Básicamente hay cuatro pines a tener en cuenta: Serial data out       ( RC7), Serial Data in(RB0), Serial Clock (RB1) y Slave select (RA5).
Para enviar los datos del potenciometro uso también el modulo SPI? ( no se si se puede considerar el potenciometro como periférico). Como leo y envió los datos del potenciometro?
Si la respuesta es que si, las funcionen para enviar, recibir etc... me imagino que tengo que sacarlas de la librería spi de Hi-tech picc18 verdad?

- Por otro lado, tengo que configurar el PIC en " Sleep Mode" hasta que suceda alguna interrupción?



De momento son las dudas que me surgen. Ya he leído la información del datasheet tanto del mudo EUSART como del modulo SPI.Ahora voy a hacer una primera versión del programa a ver que dudas mas me salen.

Muchas gracias a todos de antemano.

            

  Para leer el valor del potenciómetro tendrías que usar uno de los conversores A/D del PIC. O un conversor externo.

  No se me ocurre, o mejor dicho no he trabajado nunca con el modo sleep. Sí sé que de una manera sencilla podés dejar el PIC en sleep y que se "despierte" cuando le llega una interrupción por puerto serie (que sería el pedido de información por parte del cliente).
  Pero creo que para saber si la temperatura vario de cierto valor o el pote supero x valor vas a tener que tomar lecturas constantemente y luego evaluar.

 
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado edu1989

  • PIC18
  • ****
  • Mensajes: 275
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS2
« Respuesta #2 en: 30 de Noviembre de 2010, 15:24:01 »
Tienes razon, tendre que estar monitorizando todo el rato los valores.
Por otro lado creo que lo primero que tengo que hacer es:

- Hacer una función para leer los datos del sensor y otra para que lo escriba en el puerto serie ---> Esto a partir de las funciones de la librería SPI de Hi-tech PICC18?

- Por otro lado una función para leer el valor del potenciometro y otra para que lo escriba en el puerto serie.  En este caso puedo usar el modulo SPI o lo hago con el EUSART?

Tanto del pot como del sensor, imagino que los datos vendrán en hexadecimal o ASCII... ( cuando los lea). Me pregunto si tendré que hacer alguna función para convertir los datos a decimal, creo que si...

Si alguien tiene algún ejemplo que use el modulo SPI le agradecería que me dejara el link. Voy a buscar alguno.. Muchas gracias!

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS2
« Respuesta #3 en: 30 de Noviembre de 2010, 17:57:29 »
Tienes razon, tendre que estar monitorizando todo el rato los valores.
Por otro lado creo que lo primero que tengo que hacer es:

- Hacer una función para leer los datos del sensor y otra para que lo escriba en el puerto serie ---> Esto a partir de las funciones de la librería SPI de Hi-tech PICC18?


  La lectura SPI sí a travez de funciones para SPI. Busca en www.microchipc.com
  Pero para que lo escriba en el puerto serie, son las que estabas usando en tu primer post. Para distinguir entre ambas cosas te conviene llamar UART o RS232 al que se pueda comunicar con una PC. Si es que es éso lo que querés hacer.

- Por otro lado una función para leer el valor del potenciometro y otra para que lo escriba en el puerto serie.  En este caso puedo usar el modulo SPI o lo hago con el EUSART?

  El pote lo tenés que leer mediante el conversor A/D. Y para escribirlo al UART sería igual que en el caso anterior.

Te hacés una función "putch (unsigned char)" que envie datos al puerto UART y la usas tanto para los datos del pote como para los datos del sensor.

Tanto del pot como del sensor, imagino que los datos vendrán en hexadecimal o ASCII... ( cuando los lea). Me pregunto si tendré que hacer alguna función para convertir los datos a decimal, creo que si...

Si alguien tiene algún ejemplo que use el modulo SPI le agradecería que me dejara el link. Voy a buscar alguno.. Muchas gracias!

  El valor del pote es hexa o binario o decimal... es en realidad un valor de 0 a 1023 (si es que el A/D es de 10 bits) que se almacena en una variable. Vos te tendrías que encargar de separarlo en dos bytes para poder mandarlo al UART.
  Con respecto al formato del sensor, hay que leer el datasheet del sensor.

  En www.microchipc.com vas a encontrar rutinas de SPI
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado edu1989

  • PIC18
  • ****
  • Mensajes: 275
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS232
« Respuesta #4 en: 01 de Diciembre de 2010, 13:41:46 »
Muchas gracias AngelCris, como siempre rapido y eficaz. He empezado con el programita. Lo pongo aquí para que podais hechar un vistazo.

Código: [Seleccionar]
#include <htc.h>

/* =================================================================================
Definitions
    ================================================================================= */
#define PORTBIT(adr, bit) ( (unsigned)(&adr)*8 + (bit) )

#define Idle_Low 1 // No envia datos
#define Idle_High 2 // Envia datos

#define true 1
#define false 0

#define BAUD  9600 // Configuramos la velocidad, tanto puede ser 19200 o de 9600 kbaud/s pero hay q cambiarlo tb en la simulacion de proteus
#define PIC_CLK 20000000 // Clock de 20MHz   

/* =================================================================================
Function prototypes
    ================================================================================= */
static void interrupt service_routine (void); // This is the interrupt service routine

void init_system (void);
void time_delay (unsigned int );
char output_logic(void);
char future_state_logic(void);

char leer_potenciometro(void);
char leer_sensor(void);

void serial_setup(void);
void UsartWriteText(const unsigned char *txt);
void UsartWriteChar(unsigned char ch);
unsigned char getch(void);
unsigned char UsartReadChar_nonstop(void);
unsigned char getch_available(void);
void clear_usart_errors(void);


/* =================================================================================
Global variables 
  ================================================================================= */
static bit potenciometro @ PORTBIT(PORTA, 0); // Declaración del potenciometro
static bit sensor_temperatura @ PORTBIT(PORTB, 0);
//static bit sensor_datos_salida @ PORTBIT(PORTC, 7);  // SD0 disabled in master mode (configuración como entrada)
static bit LED @ PORTBIT(PORTB, 1);


static char present_state = Idle_Low; // state variable
static char future_state = Idle_Low; // state variable

static unsigned char valor_potenciometro;
static unsigned char valor_sensor_temperatura;
static unsigned char caracter_recibido;

unsigned char dummy;

/* =================================================================================
Main function
  ================================================================================= */
void main(void){

init_system ();
valor_potenciometro=0;
valor_sensor_temperatura=0;

LED = 0;

while(1) {

valor_potenciometro=leer_potenciometro();
valor_sensor_temperatura=leer_sensor();
// Siempre voy leyendo los valores del potenciometro y del sensor. Las funciones tienen que retornar el valor en ºC y en Ohms.


output_logic();
future_state_logic();
}

}

/* =================================================================================
Function definitions
  ================================================================================= */

//*****************************************************************************
//Future_state_logic routine
//*****************************************************************************
char future_state_logic(void){

char error = 0;

switch (present_state) {
case Idle_Low:
if ((valor_sensor_temperatura<20)||(valor_potenciometro<25)){ // Menor de 20ºC o la resistencia menos a 25Kohms
future_state = Idle_High;
}
else if (getch_available()==true) // Si hay un caracter disponible recibido por el puerto serie.
{
caracter_recibido=getch();
if(caracter_recibido=='a')
{
future_state = Idle_High;
LED=1;
error=0;
}
else{
future_state=Idle_Low;
LED=0;
error=1;
}
}

break;

case Idle_High:
if (TXIF==0){ // Buffer de transmision vacio
future_state = Idle_Low;
}
else{
error=1;
}
break;


default:
error = 1;
}
return (error);
}

//*****************************************************************************
//Output logic routine
//*****************************************************************************
char output_logic(void){
unsigned char error = 1;


switch (present_state) {

case Idle_Low:
LED = 0;
error = 0;
break;

case Idle_High:
if((valor_sensor_temperatura<20)||(valor_potenciometro<25))
{
UsartWriteText(&valor_potenciometro);
UsartWriteText(&valor_sensor_temperatura);
LED=1;
error=0;
}
else if (getch_available()==true) // Si hay un caracter disponible recibido por el puerto serie.
{
caracter_recibido=getch();
if(caracter_recibido=='a')
{
UsartWriteText(&valor_potenciometro);
UsartWriteText(&valor_sensor_temperatura);
LED=1;
error=0;
}
else
LED=0;
error=1;
}
else
error=1;
LED=0;

break;


default:
error = 1;
LED=0;
break;
}

return (error);
}

//*****************************************************************************
//Init operations 
//*****************************************************************************
void init_system (void){

// Configurar el LED.
ADCON1=0x0F; // Todos los bits como digitales
TRISB=1; // Todos los pones se comportaran como salidas menos RB0 2^0=1

ADCON1 = 0x0F; // Todos los bits como digitales
TRISA=32; // SS( Select Slave) must have TRISA<5> bit set (configure as digital in ADCON1)


// Confiurar el trisb 0 como digital.
//SDI must have TRISB<0> bit set (configure as digital in ADCON1).Configurat en master mode (bit 1 cleared, en mode slave bit 1 set)
TRISB=3; // bit 0 i 1 set.
TRISC=128; // Tots els bits a 1 menys la sortida 7 (SDO)


}

//***************************************************************************
//Interrupt Service Routine (only for the generation of the FSM's CLK sisgnal
//                           using Timer0)
//***************************************************************************


static void interrupt service_routine (void){ //Interrupt is the key word here
}


//*****************************************************************************
//Time delay routine.   
//*****************************************************************************
void time_delay(unsigned int delay){

unsigned int i;
for(i = 0; i <= delay ;i++){
NOP();
}
}

//*****************************************************************************
// SERIAL SETUP 
//*****************************************************************************
void serial_setup(void){
#define SPBRG_VALUE ((PIC_CLK/(16UL*BAUD)) -1)


BRGH = 1;
BRG16 = 0;
SPBRG = SPBRG_VALUE;

SPEN=1; // Enable serial port
SYNC=0; // Asincrono

TXIE=0; // Desactivar interrupciones en tx
TXEN=1; // Enable the transmitter
TX9=0; // 8 bits transmission

RCIE=1; // Activar interrupciones en rx
RX9=0; // 8 bits reception
CREN=1; //Enable reception

/* Using interruptions...*/
GIE=1;
PEIE=1;



#define clear_usart_errors_inline \
if (OERR)
{
TXEN=0; \
TXEN=1; \
CREN=0; \
CREN=1; \
}
if (FERR) \
{
dummy=RCREG; \
TXEN=0; \
TXEN=1; \
}

}


//*****************************************************************************
// Enviar datos ( un caracter)
//*****************************************************************************

void UsartWriteChar(unsigned char ch) {
   
while(TXIF!=0) // 0 = The EUSART transmit buffer is full
      continue;
TXREG = ch;

}
//*****************************************************************************
// Enviar datos (un buffer)
//*****************************************************************************
void UsartWriteText(const unsigned char *txt){

unsigned char i = 0;
while(txt[i]!='\0') {
UsartWriteChar(txt[i]);
i++;
}

}


//*****************************************************************************
//Leer datos ( un caracter)
//*****************************************************************************

unsigned char getch(void)
{
while(RCIF!=1){ //1 = The EUSART receive buffer, RCREG, is full
CLRWDT();
clear_usart_errors_inline;
}
return RCREG;
}

//*****************************************************************************
//Leer datos (un buffer)
//*****************************************************************************
unsigned char UsartReadChar_nonstop(void) {

if(!PIR1bits.RCIF) // TRMT1 is set when TSR is empty
      return 0;   

    return RCREG;
}


//*****************************************************************************
//Comprueba si aun faltan datos o no
//*****************************************************************************
unsigned char getch_available(void)
{
if(RCIF)
return true;
else
return false;
}


//*****************************************************************************
//Errores USART
//*****************************************************************************
void clear_usart_errors(void)
{
clear_usart_errors_inline;
}


//*****************************************************************************
//Leer entradas.
//*****************************************************************************

//*****************************************************************************
//Leer bytes recibidos del bus del modulo SPI
//*****************************************************************************

char leer_sensor(void)   
{
char Byte[8];
SSPSTAT = 0b00000000;
SSPCON1 = 0b00100000;

Byte = SSPBUF;  // Guardo los datos que tengo en el buffer (despues limpiare el buffer)

return Byte
}

//*****************************************************************************
//Leer estado potenciometro
//*****************************************************************************
char leer_potenciometro (void)
{


}
[code]

He estado buscando que tamaño ocupa la temperatura y no consigo encontrarlo. He supuesto 1byte ya que no creo que hagan falta mas de 256 valores...
Por otro lado, no se muy bien como leer el potenciometro. En la libreria adc que incorpora PICC18 he visto la siguiente definicion:

/* Read ADC data
 */
#define ReadADC() ((((unsigned int)ADRESH)<<8)|(ADRESL))
#endif

pero no se muy bien como utilizarla... puedo llamarla y ya sabe que tiene que darme el valor del potenciometro?

Muchas gracias de antemano.





[/code]

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS232
« Respuesta #5 en: 01 de Diciembre de 2010, 18:31:48 »
  Unas  cositas,

  Estás habilitando las interrupciones y en la rutina de interrupción no hacés nada (salvo que todavía te falte el código, no se) y si no hacés nada en la rutina de la interrupción no te conviene habilitarlas.

  Con respecto a la rutina de ADC, ese define lo que hace es simplemente mover el valor capturado por el AD a la variable que le indiques "x = ReadADC()". Pero el ADC hay que configurarlo, seleccionar el canal, iniciar la conversión....

  Y para leer el sensor, más allá que utilices el protocolo SPI, hay que ver como es que te tenés que comunicar con el dispositivo. No se, puede ser que primero le tengas que enviar el byte 00h u otras cosas y recién después obtener el valor... Eso lo tiene que decir el datasheet del sensor.
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado edu1989

  • PIC18
  • ****
  • Mensajes: 275
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS232
« Respuesta #6 en: 02 de Diciembre de 2010, 14:52:31 »
Gracias! Esta tarde he estado dandole vueltas a la rutina del pot, de momento solo cuelgo el codigo de lo que he hecho ya que tengo que mirar bien lo del sensor.

Código: [Seleccionar]
void ad_conversor_setup(void)
{

/*1. Configure the A/D module: Configure analog pins, voltage reference and digital I/O (ADCON1)*/

ADCON1=15; // PCFG3=1,PCFG2=1,PCFG1=1,PCFG0=1. Todas las entradas digitales


/* Select A/D input channel (ADCON0) */

CHS3=0;
CHS2=0; // Seleccionamos el canal 0 (AN0) que es donde esta conectado el potenciometro
CHS1=0;
CHS0=0;


/*Select A/D acquisition time select bits (ADCON2)*/
ACQT2=;
ACQT1=;
ACQT0=;

/* Select A/D conversion clock (ADCON2)*/

ADCS2=1;
ADCS1=0;       // Clock= Fosc/4 ( Igual que el timer)
ADCS0=0;

/*Turn on A/D module (ADCON0)*/
ADON=1; // A/D converter module is enabled

/* Configure A/D interrupt*/
ADIF=0;
ADIE=1;
GIE=1;

/*Wait the required acquisition time (if required).*/

/*Start conversion*/
GO/DONE=1; // A/D conversion in progress

/*Wait for A/D conversion to complete:Waiting for the A/D interrupt*/
/*Read A/D Result registers (ADRESH:ADRESL);
clear bit ADIF, if required*/

if( ADIF==1){ //An A/D conversion completed (must be cleared in software)
palabra_low= ADRESL;
palabra_high=ADRESH;
ADIF=0;
}  


/*For next conversion, go to step 1 or step 2, as
required. The A/D conversion time per bit is
defined as TAD. A minimum wait of 3 TAD is
required before the next acquisition starts*/

}

Las principales dudas que tengo son respecto a como configurar el tiempo de adquisicion y el tiempo de conversion. No se con que criterio escogerlo, de momento he puesto alguno que me ha parecido razonable. Por otro lado, la asignacion que hago:
palabra_low=ADRESL y palabra_high=ADRESH? como los declararia, como int, los dos? O por contra no hace falta que haga esta asignacion si voy a utilitzar la funcion readadc()?


Muchas gracias AngelCris! voy a seguir pues! Un saludo a todos.

Edito: Como veis en el tiempo de adquisicion no he puesto nada, aunque lo he dejado ya preparado.
« Última modificación: 02 de Diciembre de 2010, 14:59:04 por edu1989 »

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS232
« Respuesta #7 en: 02 de Diciembre de 2010, 16:27:30 »
  En este caso en particular (que querés usar el AN0 para el pote) tendrías que configurar el AD para que dicho pin funcione como analógico. Que según la tabla en la página 260 deberías poner PCFG3...PDFG0 en 1110.

  El tiempo tiene que cumplir con los requisitos mínimos especificados en el datasheet. En las páginas 264 y 265 muestra como calcularlo.

  Si vas a utilizar la función ReadADC(); sólo es necesario utilizar una variable y como el valor capturado por el ADC es de 10 bits y positivos, tu variable tendría que ser unsigned int.
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado edu1989

  • PIC18
  • ****
  • Mensajes: 275
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS232
« Respuesta #8 en: 03 de Diciembre de 2010, 06:42:43 »
Holaa de nuevo,muchas gracias por contestar tan rapido!. Ya he arreglado lo que me has dicho menos lo del tiempo que lo estoy mirando. Antes de todo en el proteus, el potenciometro tiene que ir conectado por una de las patas de los lados a un condensador ( de descarga) no? y desde la pata del centro del pot al pin AN0.

Antes de todo pongo una tabla donde pongo que sera cada cosa para que resulte mas claro:

Tacq= Tiempo adquisicion
Tamp= Amplifier Settling time
Tc=Holding Capacitor Charging Time
Tcoff= Temperature coefficient

Visto esto, vamos a ver la formula:


TACQ = TAMP + TC + TCOFF

Donde:
TAMP = 0.2 μs -----> Siempre es este valor? me imagino que si porque tampoco hay manera de saberlo y debe ser fijo.

TCOFF = (Temp – 25°C)(0.02 μs/°C) -----> en el datasheet lo calcula para una temperatura de 85º. Tengo que ponerme en el peor caso o con menos temperatura ya estara bien?

TC = -(CHOLD)(RIC + RSS + RS) ln(1/2048) μs ---> CHold me imagino que es el valor del condensador pero las tres resistencias no se donde habria que ponerlas...

A partir de estos calculalos podria calcular el tiempo de adquisicion que es el valor que va en los bits ACQT2,ACQT1,ACQT0 pero el clock (bits ADCS2,ADCS1,ADCS0 como lo escojo? No veo ninguna relacion entre el tiempo de clock y el tiempo de adquisicion.. me imagino que los dos tienen que ser parecidos para no notar la diferencia pero nada mas...

Muchas gracias por la ayuda de antemano. Saludos!

Edito: Pongo el codigo de lo nuevo que he hecho, ya he hecho la funcion para leer tanto el pot como la del sensor:

Código: [Seleccionar]
#include <htc.h>
#include "spi.h"
#include "adc.h"

/* =================================================================================
Definitions
    ================================================================================= */
#define PORTBIT(adr, bit) ( (unsigned)(&adr)*8 + (bit) )

#define Idle_Low 1 // No envia datos
#define Idle_High 2 // Envia datos

#define true 1
#define false 0

#define BAUD  9600 // Configuramos la velocidad, tanto puede ser 19200 o de 9600 kbaud/s pero hay q cambiarlo tb en la simulacion de proteus
#define PIC_CLK 4000000 // Clock de 4MHz (Cristal)

/* =================================================================================
Function prototypes
    ================================================================================= */
static void interrupt service_routine (void); // This is the interrupt service routine

void init_system (void);
void time_delay (unsigned int );
char output_logic(void);
char future_state_logic(void);

void sensor_setup(void);
void ad_conversor_setup(void);
void serial_setup(void);

void UsartWriteText(const unsigned char *txt);
void UsartWriteChar(unsigned char ch);
unsigned char getch(void);
unsigned char UsartReadChar_nonstop(void);
unsigned char getch_available(void);
void clear_usart_errors(void);


/* =================================================================================
Global variables 
  ================================================================================= */
static bit potenciometro @ PORTBIT(PORTA, 0); // Declaración del potenciometro
static bit sensor_temperatura @ PORTBIT(PORTB, 0);
//static bit sensor_datos_salida @ PORTBIT(PORTC, 7);  // SD0 disabled in master mode (configuración como entrada)
static bit LED @ PORTBIT(PORTB, 1);


static char present_state = Idle_Low; // state variable
static char future_state = Idle_Low; // state variable

static unsigned int valor_potenciometro;
static unsigned int valor_sensor_temperatura;

static unsigned char caracter_recibido;

unsigned char dummy;
static unsigned int palabra_low;
static unsigned int palabra_high;

/* =================================================================================
Main function
  ================================================================================= */
void main(void){

init_system ();

valor_potenciometro=0;
valor_sensor_temperatura=0;
LED = 0;

while(1) {

sensor_setup();
ad_conversor_setup();

valor_potenciometro=ReadADC();   // Libreria adc.h de PICC18
valor_sensor_temperatura=ReadSPI1();  //Libreria spi.h de PICC18

output_logic();
future_state_logic();
}

}

/* =================================================================================
Function definitions
  ================================================================================= */

//*****************************************************************************
//Future_state_logic routine
//*****************************************************************************
char future_state_logic(void){

char error = 0;

switch (present_state) {
case Idle_Low:
if ((valor_sensor_temperatura<20)||(valor_potenciometro<25)){ // Menor de 20ºC o la resistencia menos a 25Kohms
future_state = Idle_High;
}
else if (getch_available()==true) // Si hay un caracter disponible recibido por el puerto serie.
{
caracter_recibido=getch();
if(caracter_recibido=='a')
{
future_state = Idle_High;
LED=1;
error=0;
}
else{
future_state=Idle_Low;
LED=0;
error=1;
}
}

break;

case Idle_High:
if (TXIF==0){ // Buffer de transmision vacio
future_state = Idle_Low;
}
else{
error=1;
}
break;


default:
error = 1;
}
return (error);
}

//*****************************************************************************
//Output logic routine
//*****************************************************************************
char output_logic(void){
unsigned char error = 1;


switch (present_state) {

case Idle_Low:
LED = 0;
error = 0;
break;

case Idle_High:
if((valor_sensor_temperatura<20)||(valor_potenciometro<25))
{
UsartWriteText(&valor_potenciometro);
UsartWriteText(&valor_sensor_temperatura);
LED=1;
error=0;
}
else if (getch_available()==true) // Si hay un caracter disponible recibido por el puerto serie.
{
caracter_recibido=getch();
if(caracter_recibido=='a')
{
UsartWriteText(&valor_potenciometro);
UsartWriteText(&valor_sensor_temperatura);
LED=1;
error=0;
}
else
LED=0;
error=1;
}
else
error=1;
LED=0;

break;


default:
error = 1;
LED=0;
break;
}

return (error);
}

//*****************************************************************************
//Init operations 
//*****************************************************************************
void init_system (void)
{

TRISB=1; //LED. Todos los pines se comportaran como salidas menos RB0 2^0=1
TRISA=32; // SS( Select Slave) must have TRISA<5> bit set
TRISB=1; // SDI. El bit 0 a 1.Configurado en master mode (bit 1 cleared, en mode slave bit 1 set)
TRISC=128; // SDO. Tots els bits a 1 menys la sortida 7

}


//*****************************************************************************
//Time delay routine.   
//*****************************************************************************
void time_delay(unsigned int delay){

unsigned int i;
for(i = 0; i <= delay ;i++){
NOP();
}
}

//*****************************************************************************
// SERIAL SETUP 
//*****************************************************************************
void serial_setup(void){
#define SPBRG_VALUE ((PIC_CLK/(16UL*BAUD)) -1)


BRGH = 1;
BRG16 = 0;
SPBRG = SPBRG_VALUE;

SPEN=1; // Enable serial port
SYNC=0; // Asincrono

TXIE=0; // Desactivar interrupciones en tx
TXEN=1; // Enable the transmitter
TX9=0; // 8 bits transmission

RCIE=1; // Activar interrupciones en rx
RX9=0; // 8 bits reception
CREN=1; //Enable reception


/* Using interruptions...*/
/*
GIE=1;
PEIE=1;
*/


#define clear_usart_errors_inline \
if (OERR)
{
TXEN=0; \
TXEN=1; \
CREN=0; \
CREN=1; \
}
if (FERR) \
{
dummy=RCREG; \
TXEN=0; \
TXEN=1; \
}

}


//*****************************************************************************
// Enviar datos ( un caracter)
//*****************************************************************************

void UsartWriteChar(unsigned char ch) {
   
while(TXIF!=0) // 0 = The EUSART transmit buffer is full
      continue;
TXREG = ch;

}
//*****************************************************************************
// Enviar datos (un buffer)
//*****************************************************************************
void UsartWriteText(const unsigned char *txt){

unsigned char i = 0;
while(txt[i]!='\0') {
UsartWriteChar(txt[i]);
i++;
}

}

//*****************************************************************************
//Leer datos ( un caracter)
//*****************************************************************************

unsigned char getch(void)
{
while(RCIF!=1){ //1 = The EUSART receive buffer, RCREG, is full
CLRWDT();
clear_usart_errors_inline;
}
return RCREG;
}

//*****************************************************************************
//Leer datos (un buffer)
//*****************************************************************************
unsigned char UsartReadChar_nonstop(void) {

if(!PIR1bits.RCIF) // TRMT1 is set when TSR is empty
      return 0;   

    return RCREG;
}


//*****************************************************************************
//Comprueba si aun faltan datos o no
//*****************************************************************************
unsigned char getch_available(void)
{
if(RCIF)
return true;
else
return false;
}


//*****************************************************************************
//Errores USART
//*****************************************************************************
void clear_usart_errors(void)
{
clear_usart_errors_inline;
}


//*****************************************************************************
//Leer entradas.
//*****************************************************************************

//*****************************************************************************
//Leer bytes recibidos del bus del modulo SPI
//*****************************************************************************

void sensor_setup(void)  // SPI Master mode:
{

static unsigned int Byte;

SSPEN=1;    //Enables serial port and configures SCK, SDO, SDI and SS as serial port pins
BF=0;        //Receive not complete, SSPBUF is empty

//SCK is the clock output (Master Mode)
//Clock Polarity(Idle state of SCK)

SMP=1;      //Input data sampled at end of data output time
CKE=0;      //Transmit occurs on transition from Idle to active clock state

SSPM3=0;
SSPM2=0; //SPI Master mode, clock = FOSC/4
SSPM1=0;
SSPM0=0;

CKP=0; //Idle state for clock is a low level

SSPIF=0;   
if((BF==1)&&(SSPIF==1)){ //Receive complete, SSPBUF is full && The transmission/reception is complete (must be cleared in software)
Byte = SSPBUF; // Guardo los datos que tengo en el buffer (despues limpiare el buffer)
BF=0;
}

SSPIF=0; ////Waiting to transmit/receive

//return Byte
}




void ad_conversor_setup(void)
{

ADCON1=14; // PCFG3=1,PCFG2=1,PCFG1=1,PCFG0=0. Todas las entradas digitales


CHS3=0;
CHS2=0; // Seleccionamos el canal 0 (AN0) que es donde esta conectado el potenciometro
CHS1=0;
CHS0=0;

//Tiempo de adquisicion
ACQT2=0;
ACQT1=0;  // 2Tad> Fosc (Considerando Tadq=2.45us)
ACQT0=1;



ADCS2=0;
ADCS1=0;       // Clock= Fosc/2 (El mas pequeño posible)
ADCS0=0;


ADON=1; // A/D converter module is enabled

/* Configure A/D interrupt*/
ADIF=0;
ADIE=1;
GIE=1;

/*Wait the required acquisition time (if required).*/


GO/DONE=1; // A/D conversion in progress

/*Wait for A/D conversion to complete:Waiting for the A/D interrupt*/
/*Read A/D Result registers (ADRESH:ADRESL);
clear bit ADIF, if required*/

if( ADIF==1){ //An A/D conversion completed (must be cleared in software)
palabra_low= ADRESL;
palabra_high=ADRESH;
ADIF=0;
}   


}
« Última modificación: 03 de Diciembre de 2010, 08:15:46 por edu1989 »

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS232
« Respuesta #9 en: 03 de Diciembre de 2010, 10:13:33 »
Holaa de nuevo,muchas gracias por contestar tan rapido!. Ya he arreglado lo que me has dicho menos lo del tiempo que lo estoy mirando. Antes de todo en el proteus, el potenciometro tiene que ir conectado por una de las patas de los lados a un condensador ( de descarga) no? y desde la pata del centro del pot al pin AN0.

Antes de todo pongo una tabla donde pongo que sera cada cosa para que resulte mas claro:

Tacq= Tiempo adquisicion
Tamp= Amplifier Settling time
Tc=Holding Capacitor Charging Time
Tcoff= Temperature coefficient

Visto esto, vamos a ver la formula:


TACQ = TAMP + TC + TCOFF

Donde:
TAMP = 0.2 μs -----> Siempre es este valor? me imagino que si porque tampoco hay manera de saberlo y debe ser fijo.

TCOFF = (Temp – 25°C)(0.02 μs/°C) -----> en el datasheet lo calcula para una temperatura de 85º. Tengo que ponerme en el peor caso o con menos temperatura ya estara bien?

TC = -(CHOLD)(RIC + RSS + RS) ln(1/2048) μs ---> CHold me imagino que es el valor del condensador pero las tres resistencias no se donde habria que ponerlas...

A partir de estos calculalos podria calcular el tiempo de adquisicion que es el valor que va en los bits ACQT2,ACQT1,ACQT0 pero el clock (bits ADCS2,ADCS1,ADCS0 como lo escojo? No veo ninguna relacion entre el tiempo de clock y el tiempo de adquisicion.. me imagino que los dos tienen que ser parecidos para no notar la diferencia pero nada mas...

Muchas gracias por la ayuda de antemano. Saludos!

Edito: Pongo el codigo de lo nuevo que he hecho, ya he hecho la funcion para leer tanto el pot como la del sensor:

..........


  El pote lo tenés que conectar así: un extremo a GND, el otro extremo VCC y el medio a la entrada analógica. Entre el pin del medio y el terminal del PIC iría RS.

  Tamp: es fijo.
  TCoff: yo lo pondría en el pero de los casos que te puedan pasar. Por ejemplo donde estoy yo, la temperatura nunca superó los 50º (y ya estoy exagerando).
 
   Las tres resistencias que mencionás son:
   RSS: la interna del "sampling switch" y en la figura 21-3 que está en la página 263 hay un diagrama en ejes cartesianos que muestra el valor de dicha resistencia dependiendo de la tensión de alimentación del PIC
   RIC: dice que es la de interconexión y es menor o igual a 1K
   RS: es la resistencia que vos pongas en seria a tu señal a medir y según el primer párrafo de la página 264 el máximo valor recomendado para esta resistencia es de 2.5K

  El tiempo este calculado es la espera entre que seleccionamos el canal y podemos comenzar la conversión. En el 16F87xA, uno tenía que hacer la espera manualmente, pero por lo que yo entiendo en el datasheet del 18Fxxx podemos configurar esta espera con los bits ACQT2...ACQT0 y entonces automáticamente el conversor espera el tiempo configurado.
  Fijate que en la página 261, muestra según el valor de dichos bits 0TAD, 2TAD, 4TAD.... En la página 265 habla de como seleccionar el clock para la conversión, ahí menciona que el tiempo de conversión por bit está definido como TAD y que necesita 11TAD de tiempo para poder hacer una conversión de 10 bits. Entonces hay que escoger un clock que asegure un TAD mínimo. Para ello hay que referirse a la tabla 28-29 y allí indica que el TAD mínimo es de 0.7us.
  Volviendo a la página 265, hay una tabla que muestra unos ejemplos de selección de clock. Y te muestra la frecuencia máxima a la cual podría operar el PIC con esa selección de clock.
  En tu programa tenés definido un cristal de 4MHz, entonces la selección de clock para el AD y que cumpla con el TAD mínimo sería 4TOSC.
   TOSC: es el tiempo de oscilación del cristal. Como tenés 4MHz dicho tiempo es 1/4MHz = 250ns
   Como el TAD mínimo es de 0.7us, al elegir un clock AD de 4TOSC te da un TAD de 1u así que te asegurás que cumplís con el TAD mínimo.

  Pasando a tu programa veo que tenés en el while() tanto el setup_spi como el setup AD. Eso no es necesario, de hecho te conviene configurarlo sólo una vez y después hacés las lecturas en el while.

  Me cansé de escribir  :) Me voy a tomar unos mates
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado edu1989

  • PIC18
  • ****
  • Mensajes: 275
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS232
« Respuesta #10 en: 03 de Diciembre de 2010, 11:18:09 »
Holaa de nuevo! Muchas gracias.
Primero de todo he calculado el Tad:
Tamp=0.2us
Tcoff(con temp 50ºC)= 0.5us
Tc (Chold=25pF, Rss(5V)=2Kohm, Ric=1kohm,Rs=2kohm) = 0.95us

Por tanto Tad= Tamp+Tcoff+Tc= 1.65us. Hasta aquí, todo correcto? Cumplo la condicion de que el Tad minimo es de 0.7us

Con Fosc=4Mhz. Como has dicho antes hay que definir un clock para el Tad. Por tanto puedo escoger 000 = 0 TAD(1)  (ACQT2:ACQT0) ya que es superior a los 0.7us no? si escojo eso el Tad es equivalente a un tiempo de instruccion 0.25us

Como clock de conversion.. (minimo 11Tad):
11Tad= 18.15us si escogiese 110 = FOSC/64 me saldria 16us y no llegaria a cumplir los 18.15us... no se si me explico...
Estoy haciendo algo mal?

P.d: Si puedes mirarte la parte del codigo del SPI, te lo agradeceria mucho! voy a seguir trabajando, muchas gracias por la ayuda. Que disfrutes esos mates!
« Última modificación: 03 de Diciembre de 2010, 11:24:56 por edu1989 »

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS232
« Respuesta #11 en: 03 de Diciembre de 2010, 12:47:54 »
Holaa de nuevo! Muchas gracias.
Primero de todo he calculado el Tad:
Tamp=0.2us
Tcoff(con temp 50ºC)= 0.5us
Tc (Chold=25pF, Rss(5V)=2Kohm, Ric=1kohm,Rs=2kohm) = 0.95us

Por tanto Tad= Tamp+Tcoff+Tc= 1.65us. Hasta aquí, todo correcto? Cumplo la condicion de que el Tad minimo es de 0.7us


  El tiempo así calculado no se llama TAD sino TACQ, fijate en la fórmula de la página 264, y es el tiempo de adquisición.
Fijate que los bits para configurar el tiempo de adquisición se llaman ACQT2...ACQT0.
Con dichos bits tenés que configurar un tiempo que sea >= al tiempo calculado por la fórmula anterior.

Con Fosc=4Mhz. Como has dicho antes hay que definir un clock para el Tad. Por tanto puedo escoger 000 = 0 TAD(1)  (ACQT2:ACQT0) ya que es superior a los 0.7us no? si escojo eso el Tad es equivalente a un tiempo de instruccion 0.25us

Como clock de conversion.. (minimo 11Tad):
11Tad= 18.15us si escogiese 110 = FOSC/64 me saldria 16us y no llegaria a cumplir los 18.15us... no se si me explico...
Estoy haciendo algo mal?

  Estás confundiendo el TAD con el TAQC.

  Vayamos de vuelta.... Comencemos con el cálculo del TAD:

  El TAD es el tiempo de conversión por bit (que según el datasheet tiene que ser >= 0.7 us). Este tiempo lo tenés que calcular en base a la frecuencia de oscilación que estés utilizando. Los bits que configuran este tiempo son ADCS2..ADCS0 del registro ADCON2.
  En la página 261 donde están las posibles combinaciones de estos bits dice:

  ADCS2...ADCS0  Estos bits dan la frecuencia de clock del AD; para calcular el TAD hacés 1/clock AD

  111 = FRC        (clock derivado de un oscilador RC interno)
  110 = Fosc/64   (esto es lo mismo que decir Tosc*64)
  101 = Fosc/16   (esto es lo mismo que decir Tosc*16)
  100 = Fosc/4     (esto es lo mismo que decir Tosc*4)
  011 = FRC         (clock derivado de un oscilador RC interno)
  010 = Fosc/32   (esto es lo mismo que decir Tosc*32)
  001 = Fosc/8     (esto es lo mismo que decir Tosc*8 )
  000 = Fosc/2     (esto es lo mismo que decir Tosc*2)

  Ejemplo si tu cristal es de 4MHz, Fosc = 4MHz --> Tosc = 1/4MHz --> Tosc = 250ns. 
 
  Estos bits serán los que te den el tiempo de TAD al cual va a trabajar tu AD (siempre teniendo en cuenta que sea >= 0.7us). Entonces el cálculo sería de la siguiente forma  TAD = x (siendo x una de las posibles combinaciones de los bits) * Tosc. Como sabemos que TAD tiene que ser >= 0.7us -->  x * Tosc >= 0.7us, en tu caso Tosc = 250ns así que  x * 250ns >= 0.7us. La combinación mínima que cumple con esta condición es 100 porque es  4 * 250ns --> 1us que es >= 0.7us.
  Así calculaste el TAD y el clock del AD.


  Ahora pasemos al cálculo del TAQC (que es el tiempo mínimo de adquisición):

  Este tiempo se calcula con la fórmula que ya sabés y es TAQC = Tamp+Tcoff+Tc, utilizando los valores que vos das como ejemplo...

Tamp=0.2us
Tcoff(con temp 50ºC)= 0.5us
Tc (Chold=25pF, Rss(5V)=2Kohm, Ric=1kohm,Rs=2kohm) = 0.95us

nos queda que TAQC = 0.2us + 0.5 us + 0.95 us --> TAQC = 1.65us

Entonces tiempo de adquisición calculado es TAQC = 1.65us

Para configurar este tiempo tenés los bits ACQT2...ACQT0 y sus posibles combinaciones son:

111       (20TAD)
110       (16TAD)
101       (12TAD)
100       (8TAD)
011       (6TAD)
010       (4TAD)
001       (2TAD)
000       (0TAD)

  Hay que escoger una combinación que de un valor superior al TAQC calculado, para asegurarnos que funcione bien el AD.

Entonces TAQC(configurado) >= TAQC(calculado); 
TAQC(configurado) = x (siendo x una de las posibles combinaciones) * TAD(calculado).  Recordemos que el TAD(calculado) nos dio 1us, entonces TAQC(configurado) = x * 1us. Uniendo fórmulas.... x * 1us >= 1.65us. La combinación mínima que cumple con esta condición es 001 (que justamente dice 2TAD) entonces nuestra fórmula quedaría

TAQC(configurado) 001 --> TAQC(configurado) = 2TAD --> TAQC(configurado) = 2 * 1us --> TAQC(configurado) = 2 us

Esto cumple la condición TAQC(configurado) >= TAQC(calculado) ya que TAQC(configurado) = 2us y TAQC(calculado) = 1.65us
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado edu1989

  • PIC18
  • ****
  • Mensajes: 275
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS232
« Respuesta #12 en: 03 de Diciembre de 2010, 13:13:43 »
Muchas gracias AngelCris! ahora me ha quedado clarisimo.Siento la confusion de la primera parte. Lo entendia bien pero me confundi en escribir.
Ahora mismo cuelgo el programita otra vez.

Edito para subir el codigo...
-He estado mirando eso de transmitir una palabra previamente al mensaje.. y no he visto nada de eso en el datasheet. He seguido un proceso que hay en el datasheet para hacer el sensor_setup.
- La ultima parte de la funcion adc_setup asigna el valor de ADRESH y ADRESL  a dos variables. Esta bien hecha la asignacion?
- Por otra parte creo que debo modificar las funciones que tengo hechas para enviar por el puerto serie ya que las tengo hechas para un char y voy a transmitir int, concretamente unsigned int no?


Código: [Seleccionar]
#include <htc.h>
#include "spi.h"
#include "adc.h"

/* =================================================================================
Definitions
    ================================================================================= */
#define PORTBIT(adr, bit) ( (unsigned)(&adr)*8 + (bit) )

#define Idle_Low 1 // No envia datos
#define Idle_High 2 // Envia datos

#define true 1
#define false 0

#define BAUD  9600 // Configuramos la velocidad, tanto puede ser 19200 o de 9600 kbaud/s pero hay q cambiarlo tb en la simulacion de proteus
#define PIC_CLK 4000000 // Clock de 4MHz (Cristal)

/* =================================================================================
Function prototypes
    ================================================================================= */
static void interrupt service_routine (void); // This is the interrupt service routine

void init_system (void);
void time_delay (unsigned int );
char output_logic(void);
char future_state_logic(void);

void sensor_setup(void);
void ad_conversor_setup(void);
void serial_setup(void);

void UsartWriteText(const unsigned char *txt);
void UsartWriteChar(unsigned char ch);
unsigned char getch(void);
unsigned char UsartReadChar_nonstop(void);
unsigned char getch_available(void);
void clear_usart_errors(void);


/* =================================================================================
Global variables 
  ================================================================================= */
static bit potenciometro @ PORTBIT(PORTA, 0); // Declaración del potenciometro
static bit sensor_temperatura @ PORTBIT(PORTB, 0);
//static bit sensor_datos_salida @ PORTBIT(PORTC, 7);  // SD0 disabled in master mode (configuración como entrada)
static bit LED @ PORTBIT(PORTB, 1);


static char present_state = Idle_Low; // state variable
static char future_state = Idle_Low; // state variable

static unsigned int valor_potenciometro;
static unsigned int valor_sensor_temperatura;

static unsigned char caracter_recibido;

unsigned char dummy;
static unsigned int palabra_low;
static unsigned int palabra_high;

/* =================================================================================
Main function
  ================================================================================= */
void main(void){

init_system ();

valor_potenciometro=0;
valor_sensor_temperatura=0;
LED = 0;

sensor_setup();
ad_conversor_setup();

while(1) {

valor_potenciometro=ReadADC();   // Libreria adc.h de PICC18
valor_sensor_temperatura=ReadSPI1();  //Libreria spi.h de PICC18

output_logic();
future_state_logic();
}

}

/* =================================================================================
Function definitions
  ================================================================================= */

//*****************************************************************************
//Future_state_logic routine
//*****************************************************************************
char future_state_logic(void){

char error = 0;

switch (present_state) {
case Idle_Low:
if ((valor_sensor_temperatura<20)||(valor_potenciometro<25)){ // Menor de 20ºC o la resistencia menos a 25Kohms
future_state = Idle_High;
}
else if (getch_available()==true) // Si hay un caracter disponible recibido por el puerto serie.
{
caracter_recibido=getch();
if(caracter_recibido=='a')
{
future_state = Idle_High;
LED=1;
error=0;
}
else{
future_state=Idle_Low;
LED=0;
error=1;
}
}

break;

case Idle_High:
if (TXIF==0){ // Buffer de transmision vacio
future_state = Idle_Low;
}
else{
error=1;
}
break;


default:
error = 1;
}
return (error);
}

//*****************************************************************************
//Output logic routine
//*****************************************************************************
char output_logic(void){
unsigned char error = 1;


switch (present_state) {

case Idle_Low:
LED = 0;
error = 0;
break;

case Idle_High:
if((valor_sensor_temperatura<20)||(valor_potenciometro<25))
{
UsartWriteText(&valor_potenciometro);
UsartWriteText(&valor_sensor_temperatura);
LED=1;
error=0;
}
else if (getch_available()==true) // Si hay un caracter disponible recibido por el puerto serie.
{
caracter_recibido=getch();
if(caracter_recibido=='a')
{
UsartWriteText(&valor_potenciometro);
UsartWriteText(&valor_sensor_temperatura);
LED=1;
error=0;
}
else
LED=0;
error=1;
}
else
error=1;
LED=0;

break;


default:
error = 1;
LED=0;
break;
}

return (error);
}

//*****************************************************************************
//Init operations 
//*****************************************************************************
void init_system (void)
{

TRISB=1; //LED. Todos los pines se comportaran como salidas menos RB0 2^0=1
TRISA=32; // SS( Select Slave) must have TRISA<5> bit set
TRISB=1; // SDI. El bit 0 a 1.Configurado en master mode (bit 1 cleared, en mode slave bit 1 set)
TRISC=128; // SDO. Tots els bits a 1 menys la sortida 7

}


//*****************************************************************************
//Time delay routine.   
//*****************************************************************************
void time_delay(unsigned int delay){

unsigned int i;
for(i = 0; i <= delay ;i++){
NOP();
}
}

//*****************************************************************************
// SERIAL SETUP 
//*****************************************************************************
void serial_setup(void){
#define SPBRG_VALUE ((PIC_CLK/(16UL*BAUD)) -1)


BRGH = 1;
BRG16 = 0;
SPBRG = SPBRG_VALUE;

SPEN=1; // Enable serial port
SYNC=0; // Asincrono

TXIE=0; // Desactivar interrupciones en tx
TXEN=1; // Enable the transmitter
TX9=0; // 8 bits transmission

RCIE=1; // Activar interrupciones en rx
RX9=0; // 8 bits reception
CREN=1; //Enable reception


/* Using interruptions...*/
/*
GIE=1;
PEIE=1;
*/


#define clear_usart_errors_inline \
if (OERR)
{
TXEN=0; \
TXEN=1; \
CREN=0; \
CREN=1; \
}
if (FERR) \
{
dummy=RCREG; \
TXEN=0; \
TXEN=1; \
}

}


//*****************************************************************************
// Enviar datos ( un caracter)
//*****************************************************************************

void UsartWriteChar(unsigned char ch) {
   
while(TXIF!=0) // 0 = The EUSART transmit buffer is full
      continue;
TXREG = ch;

}
//*****************************************************************************
// Enviar datos (un buffer)
//*****************************************************************************
void UsartWriteText(const unsigned char *txt){

unsigned char i = 0;
while(txt[i]!='\0') {
UsartWriteChar(txt[i]);
i++;
}

}

//*****************************************************************************
//Leer datos ( un caracter)
//*****************************************************************************

unsigned char getch(void)
{
while(RCIF!=1){ //1 = The EUSART receive buffer, RCREG, is full
CLRWDT();
clear_usart_errors_inline;
}
return RCREG;
}

//*****************************************************************************
//Leer datos (un buffer)
//*****************************************************************************
unsigned char UsartReadChar_nonstop(void) {

if(!PIR1bits.RCIF) // TRMT1 is set when TSR is empty
      return 0;   

    return RCREG;
}


//*****************************************************************************
//Comprueba si aun faltan datos o no
//*****************************************************************************
unsigned char getch_available(void)
{
if(RCIF)
return true;
else
return false;
}


//*****************************************************************************
//Errores USART
//*****************************************************************************
void clear_usart_errors(void)
{
clear_usart_errors_inline;
}


//*****************************************************************************
//Leer entradas.
//*****************************************************************************

//*****************************************************************************
//Leer bytes recibidos del bus del modulo SPI
//*****************************************************************************

void sensor_setup(void)  // SPI Master mode:
{

static unsigned int Byte;

SSPEN=1;    //Enables serial port and configures SCK, SDO, SDI and SS as serial port pins
BF=0;        //Receive not complete, SSPBUF is empty

//SCK is the clock output (Master Mode)
//Clock Polarity(Idle state of SCK)

SMP=1;      //Input data sampled at end of data output time
CKE=0;      //Transmit occurs on transition from Idle to active clock state

SSPM3=0;
SSPM2=0; //SPI Master mode, clock = FOSC/4
SSPM1=0;
SSPM0=0;

CKP=0; //Idle state for clock is a low level

SSPIF=0;   
if((BF==1)&&(SSPIF==1)){ //Receive complete, SSPBUF is full && The transmission/reception is complete (must be cleared in software)
Byte = SSPBUF; // Guardo los datos que tengo en el buffer (despues limpiare el buffer)
BF=0;
}

SSPIF=0; ////Waiting to transmit/receive

//return Byte
}




void ad_conversor_setup(void)
{

ADCON1=14; // PCFG3=1,PCFG2=1,PCFG1=1,PCFG0=0. Todas las entradas digitales


CHS3=0;
CHS2=0; // Seleccionamos el canal 0 (AN0) que es donde esta conectado el potenciometro
CHS1=0;
CHS0=0;

//Tiempo de adquisicion
ACQT2=0;
ACQT1=0;  // 2Tad (Tad=1us) Por tanto 2x1us =2us >= 1.65us( Tacq calculado teoricamente)
ACQT0=1;



ADCS2=1;
ADCS1=0;       // Idem a 4Tosc. 4*Tosc(1us) es el primer valor que hace que sea superior a 0.7us( el minimo)
ADCS0=0;


ADON=1; // A/D converter module is enabled

/* Configure A/D interrupt*/
ADIF=0;
ADIE=1;
GIE=1;

/*Wait the required acquisition time (if required).*/


GO/DONE=1; // A/D conversion in progress

/*Wait for A/D conversion to complete:Waiting for the A/D interrupt*/
/*Read A/D Result registers (ADRESH:ADRESL);
clear bit ADIF, if required*/

if( ADIF==1){ //An A/D conversion completed (must be cleared in software)
palabra_low= ADRESL;
palabra_high=ADRESH;
ADIF=0;
}   


}

Gracias de antemano.
« Última modificación: 03 de Diciembre de 2010, 13:20:47 por edu1989 »

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS232
« Respuesta #13 en: 03 de Diciembre de 2010, 14:22:12 »
  Siguen habiendo cosas que no me cierran como por ejemplo que estás habilitando las interrupciones pero no las usas. Si habilitás las interrupciones pero nunca hacés nada en la rutina de interrupción y no borras los flag de la interrupción que se produzca vas a quedar en un ciclo cerrado porque vas a estar reentrando constantemente.

  Para enviar datos al puerto RS232, se envían de a 8 bits por lo tanto si querés enviar un int tendrías que hacer algo así

  putch (palabra_low);
  putch (palabra_high)

  Te dejo una librería de SPI  pero es para la familia 16F, así que tendrías que hacer los cambios necesarios para que funcione con la 18F

Código: C
  1. /**************************************************************************
  2. *         Libreria para protocolo SPI por HardWare para HiTech            *
  3. ***************************************************************************
  4.  
  5. ***************************************************************************
  6. *                                                                         *
  7. * En esta libreria se encuentran las siguientes funciones                 *
  8. *                                                                         *
  9. * setup_spi(int)      (inicializa el puerto SPI)                          *
  10. * write_spi(char)     (envia y lee un byte del SPI)                       *
  11. * read_spi()          (lee un byte del SPI)                               *
  12. * write_spi_int(char) (envia y lee un byte del SPI con interrupcion)      *
  13. * read_spi_int()      (lee un byte del SPI con interrupcion)              *
  14. *                                                                         *
  15. *  En esta libreria están definidos los parametros SPI_MASTER, SPI_SLAVE  *
  16. * SPI_SS_DISABLED, SPI_IDLE_L, SPI_IDLE_H, SPI_CLK_DIV4, SPI_CLK_DIV16,   *
  17. * SPI_CLK_DIV64, SPI_CLK_T2. SPI_SAMPLE_AT_END, SPI_XMIT_IDLE_TO_ACTIVE   *
  18. *                                                                         *
  19. * Dichos parametros son los que se usan en la funcion seupt_spi().        *
  20. *                                                                         *
  21. ***************************************************************************
  22.  
  23. ***************************************************************************
  24. *                                                                         *
  25. *  Para la configuracion como Maestro se pueden usar los siguientes       *
  26. * parametros, combinandolos con |                                         *
  27. * SPI_MASTER, SPI_IDLE_L, SPI_IDLE_H, SPI_CLK_DIV4, SPI_CLK_DIV16,        *
  28. * SPI_CLK_DIV64, SPI_CLK_T2, SPI_SAMPLE_AT_END, SPI_XMIT_IDLE_TO_ACTIVE   *
  29. *                                                                         *
  30. *  Para la configuracion como esclavo se pueden usar los siguientes       *
  31. * parametros, combinandolos con |                                         *
  32. * SPI_SLAVE, SPI_IDLE_L, SPI_IDLE_H, SPI_SS_DISABLED                      *
  33. *                                                                         *
  34. ***************************************************************************
  35.  
  36.  
  37.  
  38. * Ejemplo de configuracion y utilizacion
  39.  
  40.   #include "Hardspi.c"
  41.  
  42.   void main (void)
  43.   {
  44.     char lectura;
  45.  
  46.     .....
  47.     .....
  48.     .....
  49.  
  50.     setup_spi (SPI_MASTER || SPI_IDLE_L || SPI_XMIT_IDLE_TO_ACTIVE SPI_DIV4);
  51.    
  52.     write_spi (0x10);           //envia el dato 0x10 al spi
  53.     lectura = read_spi();       //leo el dato del spi
  54.     lectura = write_spi (0xFF); //envio 0xFF y a su vez guardo en lectura el dato leido
  55.   }
  56.  
  57.  
  58.  
  59. */
  60.  
  61.  
  62. #define SPI_MASTER                0x20
  63. #define SPI_SLAVE                 0x24
  64. #define SPI_SS_DISABLED           1
  65. #define SPI_IDLE_L                0
  66. #define SPI_IDLE_H                0x10
  67. #define SPI_CLK_DIV4              0
  68. #define SPI_CLK_DIV16             1
  69. #define SPI_CLK_DIV64             2
  70. #define SPI_CLK_T2                3
  71. #define SPI_SAMPLE_AT_END         0x8000
  72. #define SPI_XMIT_IDLE_TO_ACTIVE   0x4000
  73.  
  74.  
  75.  
  76. void setup_spi(unsigned int config)
  77. {
  78.   TRISC4 = 1;
  79.   SSPSTAT = config/256;
  80.   SSPCON = config &0xFF;
  81.   if (SSPM2 == 0) TRISC3 = 0;
  82.   else
  83.   {
  84.     TRISC3 = 1;
  85.     if (SSPM0 == 0) TRISA5 = 1;
  86.   }
  87. }
  88.  
  89. unsigned char write_spi (unsigned char spi_data_out)
  90. {
  91.   TRISC5 = 0;
  92.   SSPBUF = spi_data_out;
  93.   while (SSPIF==0);
  94.   SSPIF = 0;
  95.   return SSPBUF;
  96. }
  97.  
  98. unsigned char read_spi (void)
  99. {
  100.   TRISC5 = 1;
  101.   SSPBUF = 16;
  102.   while (SSPIF==0);
  103.   SSPIF = 0;
  104.   return SSPBUF;
  105. }
  106.  
  107. void write_spi_int (unsigned char spi_data_out)
  108. {
  109.   TRISC5 = 0;
  110.   SSPBUF = spi_data_out;
  111. }
  112.  
  113. void read_spi_int (void)
  114. {
  115.   TRISC5 = 1;
  116.   SSPBUF = 0;
  117. }

  Con esta librería, dentro de tu while podrías usar la función read_spi(); para leer el sensor
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado edu1989

  • PIC18
  • ****
  • Mensajes: 275
Re: enviar datos de un sensor de temperatura y de un pot por el puerto serie RS232
« Respuesta #14 en: 03 de Diciembre de 2010, 14:35:32 »
Gracias de nuevo.

Entonces si tengo algun bit que me avise cuando.. por ejemplo se acaba la conversion:
if( ADIF==1). Esto puedo tratarlo sin interrupciones no? tal y como hago a continuacion.

No se si te refieres a eso. Si es por la parte que pone "Using interruptions" esta entre /* */ como comentario.

Intentare modificar la libreria para poder usarla.
Gracias de antemano.

Edito para comentar el codigo de la libreria:
La parte de leer el sensor hecha por mi es:

Código: [Seleccionar]
SSPIF=0;   
if((BF==1)&&(SSPIF==1)){ /*Receive complete, SSPBUF is full && The transmission/reception is complete (must be cleared in software)*/

return SSPBUF;
BF=0;
}

SSPIF=0; ////Waiting to transmit/receive

La funcion leer de la libreria es:
Código: [Seleccionar]
unsigned char read_spi (void)
{
 
SSPBUF = 16; // ESTA LINEA QUE HACE?
while (SSPIF==0);
SSPIF = 0;
return SSPBUF;
}

Es equivalente...
« Última modificación: 03 de Diciembre de 2010, 15:55:38 por edu1989 »