TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: elreypic2 en 13 de Noviembre de 2018, 11:58:21
-
Que tal a todos,
Recién estoy tratando de hacer funcionar el EUSART del microcontrolador PIC16F18346 con el compilador C de CCS.
El problema con el que me enfrento que al usar la directiva #use rs232, esta no esta configurando el EUSART hardware. Lo que está realizando es una rutina por software para emular un puerto serial. Sé esto porque el mirar el código assembler generado, eso es lo que realiza. Además de que al visualizar el dato el baud rate es de 108694 bps (mi intención es configurarlo a 115200 bps). Ahora bien, si estuviera configurado el EUSART, el baud rate debería ser de 117640 bps (que tiene menos error). Se que funciona el puerto serial, pero mi problema es que es realizado por software y no por harware. Este es el código inicial:
#include <16F18346.h>
#device ADC=10
#FUSES NOEXTOSC //External Oscillator not enabled
#FUSES RSTOSC_HFINTRC //On Power-up clock running from HFINTRC
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES PUT //Power Up Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOPPS1WAY //Allows multiple reconfigurations of peripheral pins
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use delay(internal=16000000)
#use rs232(baud=115200,parity=N,xmit=PIN_B7,rcv=PIN_B5,bits=8,stream=PORT1)
#define OSC_HFINTRC_32MHZ
unsigned char i;
void main()
{
putc('P');
while(TRUE)
{
}
}
Como mencioné el código funciona perfectamente, pero no está configurando el EUSART hardware, está realizando el serial por software.
Después lo que intenté es configurarlo mediante los registros propios del microcontrolador de la siguiente manera:
#include <16F18346.h>
#device ADC=10
#FUSES NOEXTOSC //External Oscillator not enabled
#FUSES RSTOSC_HFINTRC //On Power-up clock running from HFINTRC
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES PUT //Power Up Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOPPS1WAY //Allows multiple reconfigurations of peripheral pins
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use delay(internal=16000000)
#define OSC_HFINTRC_32MHZ
#byte TRISB = 0x8D
#word ANSELB = 0x018D
#word RCREG = 0X0199
#word TXREG = 0x019A
#word RCSTA = 0x019D
#bit SPEN = RCSTA.7
#word TXSTA = 0x019E
#bit TRMT = TXSTA.1
#byte PIR1 = 0x11
#bit RCIF = PIR1.5
#word SPBRGL = 0x019B
#word SPBRGH = 0x019C
#word BAUDCON = 0x019F
#bit BRG16 = BAUDCON.3
#word MDSRC = 0x039D
#word RXPPS = 0x0E24
#word TXPPS = 0x0E25
#word RB5PPS = 0x0E9D
#word RB7PPS = 0x0E9F
void tx_data (unsigned char dat);
void main()
{
TRISB = 0x7F; //Set PortB.7 as output
ANSELB = 0; //Set portB as digital
RCSTA = 0X90; //Enable serial por and continuous receive
TXSTA =0X24; //Transmit enable and High Baud Rate enable
BAUDCON = 0x08; //16-bit Baud Rate Generator enable
SPBRGL = 33; //Set Baud rate at 115200bps (real one is 117,647 bps)
//SPBRGL = 0x9F; //Set Baur rate at 9600bps
//SPBRGH = 0X01;
RXPPS = 0x0D; //RB5 is connectect to RX from USART
RB7PPS = 0x14; //RB7 is connected to the TX of the USART
//MDSRC = 0x0A; //Modulation Source is EUSART1 TX
tx_data("R");
tx_data("O");
while(TRUE)
{
}
}
void tx_data (unsigned char dat)
{
while (TRMT==0); //Is the transmitter buffer available?
TXREG = dat; //Yes, then put data into buffer to transmit
}
Desafortunadamente en esta forma no he logrado hacer que funcione.
Me podrían ehcar una mano con esto por favor.
elreypic.
-
Yo aquí veo que el pin tx (supongo que usas el pic de 20 pins) lo tienes que elegir mediante el registro PPS. No creo que use_rs232 lo haga por ti y tampoco veo que lo estés ajustando en el main.
Lo de la frecuencia de 117640 para generarla ya tienes que usar un cristal externo con frecuencia múltiplo de rs232.
En el otro código veo que apuntas con directivas word a registros que son bytes. No sé si por ahí te pueden dar problemas.
-
Que tal remi04,
Antes que nada gracias por responder.
Yo aquí veo que el pin tx (supongo que usas el pic de 20 pins) lo tienes que elegir mediante el registro PPS. No creo que use_rs232 lo haga por ti y tampoco veo que lo estés ajustando en el main.
En realidad la directiva #use rs232 de acuerdo al manual, al definir los parámetros de xmit y rcv (que en mi caso son los puertos RB7 y RB5 respectivamente) y si el microcontrolador contiene USART por hardware lo configura automáticamente por ti, amenos que uses el parametro FORCE_SW.
Este microcontrolador contiene EUSART por hardware, por lo tanto yo esperaría que lo configura con los parametros que le estoy indicando. Pero no es así, al analizar el listing file o el assembler file, veo que está realizando la emulación del peurto serial mediante software y el baud rate generado es 108694 bps (lo he medido con un osciloscopio).
La pregunta es: ¿cómo configurar el EUSART interno mediante la directiva #use rs232?
Lo de la frecuencia de 117640 para generarla ya tienes que usar un cristal externo con frecuencia múltiplo de rs232.
No estoy intentando generar ese baud rate de 117640, lo que quiero es configurar el ESUART interno con un baud rate de 115200bps, pero según la hoja de datos, la fórmula proporcionada y la frecuencia en la que está trabajando el microcontrolador (16MHz), el baudrate generado debería ser de 117640bps, es decir no puedo generar el baud rate de 115200 bps exactos hay un error del 2.12%, pero eso esta bien, ya que cae dentro de la norma del 3%.
En el otro código veo que apuntas con directivas word a registros que son bytes. No sé si por ahí te pueden dar problemas.
En esto no estoy de acuerdo contigo porque este microcontrolador tiene 32 paginas de memoria RAM y en esas páginas se encuentran los SFR (Special Function Registers), es decir, también tenemos 32 páginas de registros de función especial.
Y como te puedes dar cuenta la dirección de los registros de configuración del ESUART comienzan en la dirección 0x199 (409 decimal), este número no pude ser #byte o no encaja en un byte. Este debe ser "#word", el cual, según el manual de CCS, es del tipo int16. Es por eso que debo definir esos registros como tipo #word y NO como tipo #byte.
El que no esté de acuerdo no significa que yo tenga razón, es posible que yo esté completamente mal y no esté entendiendo esta nueva directiva. En los microcontroladores anteriores, los SFR estaban dentro de las 256 direcciones de RAM así que siempre definía tales registros usando #byte, pero ahora la RAM es mucho más grande y las direcciones son más extensas, por eso mi conclusión de usar #word.
Ayer hice más pruebas de esto y me dí cuenta que CCS está haciendo algo muy extraño, en cada ocasión que intento asignar un valor a estos registros, siempre agrega un CLRF SFR+1 o un CLRF SFR-1
Me explico, cuando hago lo siguiente:
RCREG = 0x90;
El compilador produce el siguiente código en ensamblador:
MOVLW 90h
MOVLP 03h
MOWF RCSTA
CLRF TXSTA
Ese CLRF TXSTA no debería estar allí. De hecho lo que hice fue cambiar el orden de asignación de manera consecutiva de esta manera me evité que borrara los registros siguientes. Pero sigo teniendo problemas. Y tal vez como mencionas debería usar #byte, pero no logro entender cómo, si la direcciones de los registros de configuración del EUSART cominzan en 0x199. Alguna idea?
Nuevamente gracias y sigo esperando algunas otras ideas o sugerencias.
elreypic.
-
Lo de la directiva use rs232 es cierto que configura la usart hardware salvo que:
- definas FORCE_SW
- los pines indicados no coincidan con los del módulo usart del micro.
El problema de la usart en tu micro es que uno de los pines no es fijo, se puede elegir entre dos pines distintos mediante un FUSE y configurando un registro en el main. y tal vez por eso la directiva use_rs232 puede que no esté resolviendo por hard por ese motivo.
Lo de los registros luego cuando llegue a casa te lo miro. De todas formas “creo” que las directivas #word, #byte, #bit no tienen nada que ver con la dirección donde está el registro sino con el tamaño del dato al que apuntan.
Si la posición 0xfb0a apunta a un campo de 1 byte lo normal es llamarlo con un #byte, no con un #word.
Luego te lo confirmo en casa.
-
Vale, ya en casa. Te confirmo que las directivas #byte #bit #word las tienes que elegir en funcion del tamaño del dato a apuntar, no de la memoria, esto es:
#byte OSCEN=0x91C
Te recomiendo que pruebes con la función de variables de entorno, simplifica mucho el trabajo. Por ejemplo, la anterior se puede sustituir por:
#byte OSCEN=getenv("SFR:OSCEN")
Para un bit, por ejemplo, imagina que quieres acceder al bit 4 de RC1STA, su dirección es 0x19d. el bit 4 sería CREN (Habilitar/deshabilitar recepción), lo puedes poner así:
#bit CREN=0x19d.4 con el datasheet en la mano o bien, conociendo el nombre exacto del bit:
#bit CREN=getenv("BIT:CREN")
Como vez, las direcciones son de 16 bits, pero los datos son de 8 por eso usas macros de 8 bits.
Un caso en tu codigo es cuando pones: #bit BRG16 = BAUDCON.3
Eso así está mal.
Tendrías que poner:
#bit BRG16 = 0x19f.3 // dirección del registro BAUD1CON, bit numero 3 (BRG16)
Que igualmente lo puedes llamar por su nombre usando variables de entorno:
#bit BRG16 = getenv("BIT:BRG16")
Saludos.
-
Muchas gracias remi04. Llegando a casa me pongo a probar esto. Creo que ahí es donde tengo mi problema de configuración del EUSART.
Ya te comentaré con respecto a eso.
Por otro lado me encontré en el manual de CCS que dentro de la directive #use rs232, existe un parámetro llamado UART1A que según entiendo es para seleccionar lo spines alternativos del UART1 interno. Voy a probar esto también.
Otra vez muchas gracias.
elreypic.
-
Que tal remi04,
Te quiero agradecer la ayuda que me has brindado. Ahora tengo ambas soluciones para configurar el EUSART interno (hardware) de este microcontrolador.
Efectivamente tenías razón con lo de la directiva #byte y yo estaba equivocado al usar #word.
Solo cambié esas directivas de la siguiente manera:
#byte RCREG = 0X0199
#byte TXREG = 0x019A
#byte SPBRGL = 0x019B
#byte SPBRGH = 0x019C
#byte RCSTA = 0x019D
#byte TXSTA = 0x019E
#byte BAUDCON = 0x019F
#byte RXPPS = 0x0E24
#byte TXPPS = 0x0E25
#byte RB5PPS = 0x0E9D
#byte RB7PPS = 0x0E9F
y el EUSART interno funcionó de lujo. Muchas, muchas gracias.
La otra solución que encontré es usando la directiva #use rs232, y para esto hay que hacer lo siguiente:
#PIN_SELECT U1TX = PIN_B7
#PIN_SELECT U1RX = PIN_B5
#use delay(internal=16000000)
#use rs232(baud=115200,parity=N,xmit=PIN_B7,rcv=PIN_B5,bits=8,stream=PORT1,UART1)
Y con esto todo va de maravilla y se pueden usar las funciones de putc(), printf(), etc.
Saludos y gracias otra vez.
elreypic.
-
Me alegro muchísimo.
Un saludo.