Usar UART PIC24FJ64GB002

1

Estoy intentando configurar un PIC24FJ64GB002 para la comunicación UART en MBLAB usando XC16. Estoy usando la demostración de CDC USB para comunicarme con un dispositivo, y estoy tratando de transmitir esa información a un arduino usando el PIC. Estoy confundido en cuanto a qué frecuencia se está ejecutando la CPU. Estoy usando un cristal externo de 8 MHZ, con varios bits establecidos en la demostración. Aquí se establecen los bits relacionados con el oscilador.

#include <p24FJ64GB002.h>
#include "system.h"
#include "usb.h"

/** CONFIGURATION Bits **********************************************/
_CONFIG1(
    WDTPS_PS1 &
    FWPSA_PR32 &
    WINDIS_OFF &
    FWDTEN_OFF &
    ICS_PGx1 &
    GWRP_OFF &
    GCP_OFF &
    JTAGEN_OFF
)

_CONFIG2(
    POSCMOD_HS &
    I2C1SEL_PRI &
    IOL1WAY_OFF &
    OSCIOFNC_ON &
    FCKSM_CSDCMD &
    FNOSC_PRIPLL &
    PLL96MHZ_ON &
    PLLDIV_DIV2 &
    IESO_OFF
)

_CONFIG3(
    WPFP_WPFP0 &
    SOSCSEL_SOSC &
    WUTSEL_LEG &
    WPDIS_WPDIS &
    WPCFG_WPCFGDIS &
    WPEND_WPENDMEM
)

_CONFIG4(
    DSWDTPS_DSWDTPS3 &
    DSWDTOSC_LPRC &
    RTCOSC_SOSC &
    DSBOREN_OFF &
    DSWDTEN_OFF
)

/*********************************************************************
* Function: void SYSTEM_Initialize( SYSTEM_STATE state )
*
* Overview: Initializes the system.
*
* PreCondition: None
*
* Input:  SYSTEM_STATE - the state to initialize the system into
*
* Output: None
*
********************************************************************/
void SYSTEM_Initialize( SYSTEM_STATE state )
{
    //On the PIC24FJ64GB004 Family of USB microcontrollers, the PLL will not power up and be enabled
    //by default, even if a PLL enabled oscillator configuration is selected (such as HS+PLL).
    //This allows the device to power up at a lower initial operating frequency, which can be
    //advantageous when powered from a source which is not gauranteed to be adequate for 32MHz
    //operation.  On these devices, user firmware needs to manually set the CLKDIV<PLLEN> bit to
    //power up the PLL.
    {
        unsigned int pll_startup_counter = 600;
        CLKDIVbits.PLLEN = 1;
        while(pll_startup_counter--);
    }

    switch(state)
    {
        case SYSTEM_STATE_USB_HOST:
            PRINT_SetConfiguration(PRINT_CONFIGURATION_LCD);
            break;

        case SYSTEM_STATE_USB_HOST_CDC_BASIC:
            BUTTON_Enable(BUTTON_USB_HOST_CDC_BASIC);
            PRINT_SetConfiguration(PRINT_CONFIGURATION_LCD);
            break;
    }
}

Luego uso esta función para inicializar UART

void UART_INIT()
{
   AD1PCFGL = 0xFFFF;
   __builtin_write_OSCCONL(OSCCON & 0xbf);
   TRISBbits.TRISB15 = 0;
   __builtin_write_OSCCONL(OSCCON | 0x40);
   RPOR7bits.RP15R = 3;
   U1BRG = 103; //set baud speed
   U1MODE   =   0x8000;  //turn on module
   U1STA    =   0x8400;  //set interrupts
   IEC0bits.U1TXIE = 0;
   IFS0bits.U1RXIF = 0;
   IFS0bits.U1TXIF = 0;
}

Y esta función para transmitir un byte

void send(char c)
{
   while(U1STAbits.UTXBF == 1);
   U1TXREG = c;
}

Estoy tratando de averiguar qué valor debe definirse FCY. Asumí que sería de 16 MHZ, (96MHz / 3) / 2, pero el código no funcionó en esa configuración. ¿Podría haber otro problema en el código?

Estoy haciendo todos los pines digitales y configurando el pin UART como una entrada con este código

__builtin_write_OSCCONL(OSCCON & 0xbf);
AD1PCFGL = 0xFFFF;
TRISBbits.TRISB15 = 0;
UART_INIT(9600);
__builtin_write_OSCCONL(OSCCON | 0x40);

Finalmente, uso las funciones como esta

UART_INIT(9600); 

while(1) 
{ 
send('H'); 
send('e'); 
send('l'); 
send('l'); 
send('o'); 
send(' '); 
send('W'); 
send('o'); 
send('r'); 
send('l'); 
send('d'); 
send('\n'); 
} 
    
pregunta popgalop

5 respuestas

2

Un diagrama ayudaría a transmitir lo que estás haciendo. Creo que esto es lo que has implementado:

"un dispositivo" (dispositivo USB) < - > USB < - > PIC24FJ64BG002 (host USB) < - > UART < - > Arduino

Echemos un vistazo a las opciones de reloj para esta parte:

TambiénveamosmásdecercalascosasespecíficasdelrelojUSB:

CONFIG2contienetuscosasrelacionadasconeloscilador:

_CONFIG2(POSCMOD_HS&I2C1SEL_PRI&IOL1WAY_OFF&OSCIOFNC_ON&FCKSM_CSDCMD&FNOSC_PRIPLL&PLL96MHZ_ON&PLLDIV_DIV2&IESO_OFF)

Recapitulandoloquesabemos:

  • Elcristaldeorigenes8MHz(entradadePOSC)
  • POSCMODestáconfiguradoenmododeosciladorHS
  • FNOSCestáconfiguradocomoOsciladorprincipal+PLL
  • PLLDIVestáconfiguradoparadividirpor2

También,apartirdelahojadedatos:

  • LaconfiguraciónpredeterminadaparaCPDIVes0x00,quesedividepor1(32MHz)

Entonces,¿cuálesnuestraconclusión?Yodiríaqueamenosquehayaotrocódigoqueensucieconlosbitsenalgunaparte,lasituaciónescomosemuestraenlafigura8.2-HSPLLseestáejecutandoa32MHz(salidade96MHzUSBPLL,divididoportres,luegodivididoporuno).

Y,porquelosabemos

\$F_{CY}=\dfrac{F_{OSC}}{2}\$

larespuestadebeser16MHz.

Ahora,asufórmuladevelocidadenbaudios:

baud=(FCY/(16*baud))-1;

(Esunamalaprácticatenerelmismonombredevariableenambosladosdelaecuación:elladoizquierdodebecambiarsunombreaBRGoalgomásparecidoaloquees:eselvalordelgeneradordelavelocidadenbaudios,nolatasaenbaudiosensí).

SibuscaelManualdereferenciadelafamiliaPIC24paraUART,encontrarálosvaloresprecalculadosparausted:

De forma predeterminada, BRGH es cero, por lo que, a menos que el código esté jugando con él, su generador de velocidad en baudios debe establecerse en 103 decimal. (Su fórmula es para BRGH - 0 y con una velocidad de reloj de 16 MHz está de acuerdo con esta tabla).

Me atrevería a adivinar y decir que los problemas de UART, si persisten, no están relacionados con el reloj ...

    
respondido por el Adam Lawrence
1

En el núcleo PIC24, FCY es la mitad de la frecuencia del oscilador. Con el cristal externo de 8 MHz, multiplicado por 4 (PLL), dividido por 2 (PLLDIV), y luego dividido por 2 una vez más (primera oración) obtendrá 8 MHz. El oscilador también está disponible en el pin REFO, puede habilitarlo y medir la frecuencia directamente usando un contador, un osciloscopio o un analizador lógico.

    
respondido por el Oleg Mazurov
1

Otras respuestas han explicado en gran medida acerca de las configuraciones, mi enfoque está en el código que está usando para UART Communication . Microchip proporciona funciones de biblioteca periférica que puede utilizar directamente en su programa en lugar de poner valores en los registros. Vaya a c\Program Files\Microchip\(your compiler)\docs ; encontrará mucha documentación o intente buscar PIC18/PIC24/PIC32 peripheral library . No he trabajado en PIC24 pero las funciones son las mismas para todas las series de MCU como PIC18 PIC24 PIC32 . Por ejemplo, para UART:

OpenUART(): to initialize UART channel.
putsUART(): to send string to your UART
getsUART(): to receive string from UART
putcUART(): to send a char.
getcUART(): to receive a char

puede utilizar estas funciones directamente y ahorrar su tiempo.!

Código de demostración:

/*
*
*/
int main()
{
  /*
  *
  */
  OpenUART1( UART_EN | UART_NO_PAR_8BIT | UART_1STOPBIT, UART_RX_ENABLE | UART_TX_ENABLE, (FPB/16/BAUDRATE)-1 );
  while(1)
  {
    putsUART1("Hello World");
  }
}
    
respondido por el Aircraft
0

si no está seguro de si su reloj está funcionando perfectamente, simplemente alterne un pin usando __delay_us (x) y vea si la forma de onda de salida en el osciloscopio es correcta.

y con respecto a la velocidad en baudios, la ecuación tiene un solo error (estupidez del compilador), intente esto: baudios = (FCY / (16.0 * baudios)) - 1. cuando agrega ".0" a 16, está forzando una división flotante, porque a veces el compilador realiza optimizaciones y el resultado no es correcto si se usa un entero.  Enfrenté exactamente el mismo problema anterior y esto lo resolvió.

espero que ayude

    
respondido por el ElectronS
0

Cosas para probar:

  • Deshabilitar la interrupción de transmisión y borrar el indicador de interrupción de TX
  • Calcule el valor U1BRG usted mismo e ingréselo en el registro.
  • Como no está seguro del valor FCY, intente con 4M, 8M, 16M, 32M ... hasta que uno funcione.

El código debería verse así, reorganizado un poco:

void UART_INIT()
{
   __builtin_write_OSCCONL(OSCCON & 0xbf);
   RPOR7bits.RP15R = 3;   // connect uart1 tx to RP15
   //AD1PCFGL = 0xFFFF;  //try the code with and without this line
   __builtin_write_OSCCONL(OSCCON | 0x40);
   U1BRG = 103;    //set baud value for 9600 (verify)
   IEC0bits.U1TXIE = 0;  //just in case
   IEC0bits.U1RXIE = 0;
   U1MODE   =   0x8000;  //turn on module
   U1STA    =   0x0400;  // enable TX
   IFS0bits.U1TXIF = 0;
   IFS0bits.U1RXIF = 0;
}

void send(char c)
{
   while(U1STAbits.UTXBF);
   U1TXREG = c;
}

void uart_print(const char * str){
    while (*str)
       send(*str++);
}

void main(){
    //initialize clock and other stuff here

    UART_INIT(); 
    //add a delay of 20ms here, just in case

    while(1)
       uart_print("Hello world\n");
}
    
respondido por el TisteAndii

Lea otras preguntas en las etiquetas