Verwenden Sie UART PIC24FJ64GB002

Ich versuche, einen PIC24FJ64GB002 für die UART-Kommunikation in MBLAB mit XC16 einzurichten. Ich verwende die USB-CDC-Demo, um mit einem Gerät zu kommunizieren, und ich versuche, diese Informationen mit dem PIC an ein Arduino weiterzuleiten. Ich bin verwirrt, mit welcher Frequenz die CPU läuft. Ich verwende einen externen 8-MHz-Quarz, bei dem in der Demo mehrere Bits gesetzt sind. Hier werden Bits gesetzt, die den Oszillator betreffen.

#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;
    }
}

Ich verwende dann diese Funktion, um den UART zu initialisieren

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;
}

Und diese Funktion, um ein Byte zu übertragen

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

Ich versuche herauszufinden, welcher Wert FCY definiert werden sollte. Ich nahm an, dass es 16 MHz (96 MHz / 3) / 2 sein würde, aber der Code funktionierte bei dieser Einstellung nicht. Könnte es ein anderes Problem im Code geben?

Ich mache alle Pins digital und setze den UART-Pin als Eingang mit diesem Code

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

Schließlich verwende ich die Funktionen wie folgt

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'); 
} 
In deiner CONFIG2 hast du FNOSC_PRIPLL ausgewählt. Ihre CPU wird also wahrscheinlich mit 48 MHz getaktet (wenn Sie nicht mit den CPDIV-Bits im CLKDIV-Register herumgespielt haben).
Aber PLLDIV_DIV2 ist auch gesetzt, also ist die Frequenz nicht wirklich 24 MHz, aber ich habe das versucht und es hat nicht funktioniert.
Nachdem Sie The Fine Manual etwas ausführlicher gelesen haben (und insbesondere Abschnitt 8.5 beachtet haben), scheint es, dass Sie höchstwahrscheinlich einen CPU-Takt von 32 MHz haben. Die 96-MHz-PLL benötigt einen 4-MHz-Eingang (weshalb Sie PLLDIV_DIV2 benötigen), und dieser wird durch 3 geteilt, bevor er der CPU zugeführt wird.
Das würde bedeuten, dass der FCY = 32/2 = 16 MHz ist, außer dass ich es versucht habe und nicht funktioniert.

Antworten (5)

Ein Diagramm würde helfen, zu vermitteln, was Sie tun. Ich denke, das ist, was Sie implementiert haben:

"ein Gerät" (USB-Gerät) <-> USB <-> PIC24FJ64BG002 (USB-Host) <-> UART <-> Arduino

Werfen wir einen Blick auf die Uhroptionen für diesen Teil:

Geben Sie hier die Bildbeschreibung ein

Schauen wir uns auch die USB-spezifischen Uhrensachen genauer an:

Geben Sie hier die Bildbeschreibung ein

CONFIG2 enthält Ihr oszillatorbezogenes Zeug:

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

Fassen wir zusammen, was wir wissen:

  • Ihr Quellkristall ist 8 MHz (Eingang von POSC)
  • POSCMOD ist auf den HS-Oszillatormodus eingestellt
  • FNOSC ist auf Primäroszillator + PLL eingestellt
  • PLLDIV ist auf Teilen durch 2 eingestellt

Auch aus dem Datenblatt:

  • Die Standardeinstellung für CPDIV ist 0x00, was geteilt durch 1 (32 MHz) ist.

Also, was ist unser Fazit? Ich würde sagen, dass die Situation wie in Abbildung 8.2 gezeigt ist, wenn nicht irgendwo anderer Code mit den Bits herumspielt - HSPLL läuft mit 32 MHz (96 MHz USB-PLL-Ausgang, geteilt durch drei, dann geteilt durch eins).

Und weil wir das wissen

F C Y = F Ö S C 2

die Antwort sollte 16 MHz sein.

Nun zu Ihrer Baudratenformel:

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

(Es ist eine schlechte Praxis, denselben Variablennamen auf beiden Seiten der Gleichung zu haben: Die linke Seite sollte in BRG oder etwas Ähnliches umbenannt werden - es ist der Baudratengeneratorwert, nicht die Baudrate selbst.)

Wenn Sie das Referenzhandbuch der PIC24-Familie für UART nachschlagen, finden Sie die für Sie vorberechneten Werte:

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Standardmäßig ist BRGH null, also sollte Ihr Baudratengenerator auf 103 dezimal eingestellt sein, es sei denn, der Code mischt sich damit ein. (Ihre Formel ist für BRGH - 0 und stimmt mit einer Taktrate von 16 MHz mit dieser Tabelle überein.)

Ich würde eine Vermutung wagen und sagen, dass Ihre UART-Probleme, wenn sie bestehen bleiben, nicht mit der Uhr zusammenhängen ...

Ich habe die gleichen Probleme, auch wenn ich nur 103 einstecke
Das Problem war einfach, ich hatte vergessen, die Init-Methode aufzurufen, die die PLL einschaltet, aber eine großartige Antwort.
Bingo. Wenigstens hast du es jetzt gelöst.

Im PIC24-Kern ist FCY die Hälfte der Oszillatorfrequenz. Mit externem 8-MHz-Quarz multipliziert mit 4 (PLL), geteilt durch 2 (PLLDIV) und dann noch einmal durch 2 geteilt (erster Satz) ergibt 8 MHz. Der Oszillator ist auch am REFO-Pin verfügbar, Sie können ihn aktivieren und die Frequenz direkt mit einem Zähler, Oszilloskop oder einem Logikanalysator messen.

Ich habe das versucht, aber wenn dieser Code ausgeführt wird, kommt Kauderwelsch auf dem Arduino UART_INIT (9600); while(1) { send('H'); senden('e'); senden('l'); senden('l'); senden('o'); schicken(' '); senden('W'); senden('o'); senden('r'); senden('l'); senden('d'); senden('\n'); }

Andere Antworten haben die Konfigurationseinstellungen ausführlich erklärt, mein Fokus liegt auf dem Code, den Sie für verwenden UART Communication. Microchip bietet periphere Bibliotheksfunktionen, die Sie direkt in Ihrem Programm verwenden können, anstatt Werte in Register zu schreiben. Gehen Sie zu, c\Program Files\Microchip\(your compiler)\docsdort finden Sie viele Dokumentationen oder suchen Sie nach PIC18/PIC24/PIC32 peripheral library. Ich habe nicht in PIC24 gearbeitet, aber die Funktionen sind für alle MCU-Serien wie PIC18 PIC24 PIC32. Zum Beispiel für 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

Sie können diese Funktionen direkt nutzen und sparen Zeit.!

Demo-Code:

/*
*
*/
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");
  }
}
Welcher Header muss enthalten sein, um diese Funktionen zu verwenden
@popgalop Um die Peripheriebibliothek zu verwenden, müssen Sie einschließenplib.h

Wenn Sie sich nicht sicher sind, ob Ihre Uhr perfekt funktioniert, schalten Sie einfach einen Pin mit __delay_us(x) um und sehen Sie, ob die Ausgangswellenform auf dem Oszilloskop richtig ist.

und in Bezug auf die Baudrate hat die Gleichung einen einzigen Fehler (Compiler-Dummheit), versuchen Sie Folgendes: baud = (FCY/(16.0*baud))-1 . Wenn Sie ".0" zu 16 hinzufügen, erzwingen Sie eine Float-Division , da der Compiler manchmal Optimierungen vornimmt und das Ergebnis nicht korrekt ist, wenn Integer verwendet wird. Ich hatte vorher genau das gleiche Problem und das hat es gelöst.

Ich hoffe, das hilft

Dinge zum Ausprobieren:

  • Deaktivieren Sie den Sende-Interrupt und löschen Sie das TX-Interrupt-Flag
  • Berechnen Sie den U1BRG-Wert selbst und tragen Sie ihn in das Register ein.
  • Da Sie sich über den FCY-Wert nicht sicher sind, versuchen Sie es mit 4M, 8M, 16M, 32M ... bis einer funktioniert.

Der Code sollte so aussehen, etwas anders angeordnet:

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");
}