1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PIC18F27Q43 Usart1シリアル通信

Last updated at Posted at 2024-04-24

8ビット非同期モード 8-bit Asynchronous Mode

Usart1ピンの割り付け

送信と受信のピン割り付けの設定。

送信 受信
デフォルトピン なし RC7
PPS割り付け可能ポート ポートB,ポートC ポートB,ポートC

18F27Q43には5つのUARTがあります。UART3、4は、ポートAに割り付けることができますが、ポートCに割り付けることはできなくなります。

受信のデフォルトは、RC7。
受信、送信ともに、ポートB、ポートCならどこにでも、PPSを使用して割り付け可能。
※PPS:Peripheral Pin Select Module

Usartボーレート

受信ビットのサンプリングレートを決めます。 Foscから分周します。通信速度の4倍と16倍の速度のサンプリングクロックを生成します。整数値にならないので、目標のボーレートの誤差が、3%以内になるようにBRGSを選択します。

BRGS BRG/UsartMode Baud Rate の式
1 High Rate Fosc/[4*(U1BRG+1)]
0 normal Rate Fosc/[16*(U1BRG+1)]

今回はシステムクロックFosc=32Mhz Usartのボーレートを115200bpsに設定しています。

baudrate計算式修正1.png

誤差3%以内なので、BRGS=0 で設定します。

Usart受信バッファ、Usart送信バッファ

受信バッファは2バイト、送信バッファは1バイト。 受信バッファがオーバーフローした場合、オーバーフローエラーが発生します。今回、オーバーフローエラーは、チェックしていません。

putch関数 機種依存するprintf標準入出力関数を使用する準備

printfは、stdoutに出力するとき、putch関数を使用します。デフォルトでは、putch関数は、関数名だけ与えられていて、中身が記述されていません。機種ごとに送信フラグ名が違ってくるからです。なので、PIC18F27Q43の送信フラグ名に合わせてputch関数の中身を記述する必要があります。

peripheral.c
void putch(uint8_t _txData)
{
    if(U1ERRIRbits.TXMTIF==High)//シフトレジスタ空?
    {
        do{
            U1TXB=_txData;
            while(U1ERRIRbits.TXMTIF==Low);
        }while(U1FIFObits.TXBF);//TXバッファ空になるまで送信。
    }else{
        //error operation
    }
}

getch関数 機種依存する関数

putch関数と同様に、getch関数も、受信フラグ名が機種依存しています。18F27Q43に合わせて、関数の中身を実装します。

peripheral.c
uint8_t getch(void)
{
    while(PIR4bits.U1RXIF==Low);//受信完了
    return U1RXB;
}

今回のソースコード

タイマー0でLEDを0.5秒間隔で点滅させ、同時に、カウンター値をパソコンに送信。
Usartで\nを受信したら、受信内容をそのままエコーバックさせています。

<ソースファイル>
Q_peripheral27Q43.h: タイマー、シリアル通信ヘッダーファイル
Q_peripheral27Q43.h: タイマー、シリアル通信ソースファイル
Q_interrupt27Q43.h: 割込み処理ヘッダーファイル
Q_interrupt27Q43.c: 割込み処理ソースファイル
main.c:メイン関数

Q_peripheral27Q43.h
#ifndef Q_PERIPHERAL27Q43_H
#define	Q_PERIPHERAL27Q43_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
    
#define Low 0
#define High 1
   
#define _XTAL_FREQ 32000000
#define BAUDRATE 115200
#define SET_SPBRG_DATA  (((unsigned int)((_XTAL_FREQ/4)/BAUDRATE))-1)
#define SET_SPBRG_DATA1 (((unsigned int)((_XTAL_FREQ/16)/BAUDRATE))-1)   
//USART---------------------------------------
#define RXUSART_BUFFER_SIZE 20
typedef struct
{
    uint8_t buf[RXUSART_BUFFER_SIZE];
    uint8_t length;
    uint8_t completed;
}_rxUsart;
extern _rxUsart rxUsart;
extern uint8_t usartTxData[20];
extern void usartInit(void);
extern void putch(uint8_t);
extern uint8_t getch(void);

//Timer--------------------------------------
typedef struct
{
    uint16_t cnt;
    bool fg;
}_tm;
extern _tm tm0;
extern void timer0Init(void);  

#endif
#endif	/* Q_PERIPHERAL27Q43_H */
Q_peripheral27Q43.c
#include "Q_peripheral27Q43.h"

//*****************************************************//
//USART初期化
//*****************************************************//
_rxUsart rxUsart;
void usartInit(void)
{
    //6.PPS--------------------------------------------------
    PPSLOCK = 0x55; 
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 0;//Unlock.
    
    U1RXPPS=0b010111;   //RC7:rx
    RC6PPS=0x20;        //RC6:tx
    TRISC|=0x80;        //RC7:input
    
    PPSLOCK = 0x55; 
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 1;//lock.
    
    //1.ボーレート設定115200----------------------------------
    U1BRG=SET_SPBRG_DATA1;
    //2.モード 非同期
    U1CON0bits.MODE=0b0000; //Asynchronous 8-bit USART mode
    //4.Serial port enabled
    U1CON1bits.ON=1;
    //5.Transmit is enabled. Recieve enabled.
    U1CON0bits.TXEN=1;
    U1CON0bits.RXEN=1;
    
    //7.interrupt setting------------------------------------
    PIR4bits.U1RXIF=0;
    PIE4bits.U1RXIE=1; 
    
}

void putch(uint8_t _txData)
{
    if(U1ERRIRbits.TXMTIF==High)//シフトレジスタ空?
    {
        do{
            U1TXB=_txData;
            while(U1ERRIRbits.TXMTIF==Low);
        }while(U1FIFObits.TXBF);//TXバッファ空になるまで送信。
    }else{
        //error operation
    }
}

uint8_t getch(void)
{
    while(PIR4bits.U1RXIF==Low);//受信完了
    return U1RXB;
}


//*****************************************************//
//Timer0初期化
//*****************************************************//
_tm tm0;
void timer0Init(void)
{
//Timer0初期化--------------------------------------------------
    T0CON1bits.CS=0b010;//クロックソースFosc/4
    T0CON1bits.CKPS=0b0011;//プリスケ1:8
    T0CON0bits.MD16=1;//16bitsタイマー
    T0CON0bits.OUTPS=0b0000;//ポストスケーラ1:1
    TMR0H=0xD8;//10ms Fosc=32Mhz
    TMR0L=0xF0;//10ms 
    T0CON0bits.EN=1;
    PIE3bits.TMR0IE=1;
    PIR3bits.TMR0IF=0;
}

Q_interrupt27Q43.h
#ifndef Q_INTERRUPT_H
#define	Q_INTERRUPT_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "Q_peripheral27Q43.h"
  
extern void __interrupt(irq(IRQ_U1RX)) USART1RX_ISR(void);    
extern void __interrupt(irq(IRQ_TMR0)) Timer0_ISR(void); 

#ifdef	__cplusplus
}
#endif

#endif	/* Q_INTERRUPT_H */
Q_interrupt27Q43.c
#include "Q_interrupt27Q43.h"

//****************割り込み関数***********************//
// USART1割込み
//**************************************************//
void __interrupt(irq(IRQ_U1RX)) USART1RX_ISR(void)
{
    uint8_t ch;
    PIR4bits.U1RXIF=0;
    ch=getch();
    rxUsart.buf[rxUsart.length++]=ch;
    if(rxUsart.length>RXUSART_BUFFER_SIZE)
    {
        rxUsart.length=0;
    }
    if(ch==0x0a)
    {
        rxUsart.buf[rxUsart.length-2]=0x00;
        PIE4bits.U1RXIE=0;
        rxUsart.completed=true;
    }
}

//****************割り込み関数***********************//
// Timer0割込み
//**************************************************//
void __interrupt(irq(IRQ_TMR0)) Timer0_ISR(void)
{
    PIR3bits.TMR0IF=0;
    tm0.cnt++;
    TMR0L=0xF0;//10ms
    if(tm0.cnt==50)
    {
        tm0.cnt=0;
        tm0.fg=true;
        T0CON0bits.EN=0;
        PIE3bits.TMR0IE=0;
    }
    
}
main.c
// PIC18F27Q43 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#pragma config FEXTOSC = OFF    // External Oscillator Selection (Oscillator not enabled)
#pragma config RSTOSC = HFINTOSC_64MHZ// Reset Oscillator Selection (HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1)

// CONFIG2
#pragma config CLKOUTEN = OFF   // Clock out Enable bit (CLKOUT function is disabled)
#pragma config PR1WAY = OFF     // PRLOCKED One-Way Set Enable bit (PRLOCKED bit can be set and cleared repeatedly)
#pragma config CSWEN = ON       // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)

// CONFIG3
#pragma config MCLRE = EXTMCLR  // MCLR Enable bit (If LVP = 0, MCLR pin is MCLR; If LVP = 1, RE3 pin function is MCLR )
#pragma config PWRTS = PWRT_OFF // Power-up timer selection bits (PWRT is disabled)
#pragma config MVECEN = ON      // Multi-vector enable bit (Multi-vector enabled, Vector table used for interrupts)
#pragma config IVT1WAY = ON     // IVTLOCK bit One-way set enable bit (IVTLOCKED bit can be cleared and set only once)
#pragma config LPBOREN = OFF    // Low Power BOR Enable bit (Low-Power BOR disabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled , SBOREN bit is ignored)

// CONFIG4
#pragma config BORV = VBOR_1P9  // Brown-out Reset Voltage Selection bits (Brown-out Reset Voltage (VBOR) set to 1.9V)
#pragma config ZCD = OFF        // ZCD Disable bit (ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON)
#pragma config PPS1WAY = OFF     // PPSLOCK bit One-Way Set Enable bit (PPSLOCKED bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle)
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Low Voltage Programming Enable bit (Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Extended Instruction Set and Indexed Addressing Mode disabled)

// CONFIG5
#pragma config WDTCPS = WDTCPS_31// WDT Period selection bits (Divider ratio 1:65536; software control of WDTPS)
#pragma config WDTE = OFF       // WDT operating mode (WDT Disabled; SWDTEN is ignored)

// CONFIG6
#pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)
#pragma config WDTCCS = SC      // WDT input clock selector (Software Control)

// CONFIG7
#pragma config BBSIZE = BBSIZE_512// Boot Block Size selection bits (Boot Block size is 512 words)
#pragma config BBEN = OFF       // Boot Block enable bit (Boot block disabled)
#pragma config SAFEN = OFF      // Storage Area Flash enable bit (SAF disabled)
#pragma config DEBUG = OFF      // Background Debugger (Background Debugger disabled)

// CONFIG8
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block not Write protected)
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers not Write protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not Write protected)
#pragma config WRTSAF = OFF     // SAF Write protection bit (SAF not Write Protected)
#pragma config WRTAPP = OFF     // Application Block write protection bit (Application Block not write protected)

// CONFIG10
#pragma config CP = OFF         // PFM and Data EEPROM Code Protection bit (PFM and Data EEPROM code protection disabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "Q_peripheral27Q43.h"
#include "Q_interrupt27Q43.h"
#include "Q_initialize.h"
#include "Q_I2C1v1.h"
#include "I2C_LCD.h"
#include  "MCP23017.h"


void portInit(void);
void oscillatorInit(void);
void vicInit(void);

void main(void)
{
    uint16_t val;
    //CPUハード初期化-----------------------
    portInit();
    oscillatorInit();
    vicInit();
    __delay_ms(100);
  
    //周辺機能初期化--------------------------------
    timer0Init();//LED表示
    usartInit();

    //グローバル割り込み許可------------------------------------------
    INTCON0bits.IPEN=1;//プライオリティ無し
    INTCON0bits.GIE=1;//Enable all masked interrupts
    
    val=0;
    while(1)
    {
        //Timer0割込み処理-------------------------------------
        if(tm0.fg==true)
        {
            tm0.fg=false;
            PORTCbits.RC0=~PORTCbits.RC0;
            printf("val=%d\n",val);
            val++;
            T0CON0bits.EN=1;
            PIE3bits.TMR0IE=1;
        }
        if(rxUsart.completed==true)
        {
            printf("%s\n",rxUsart.buf);
            rxUsart.length=0;
            rxUsart.completed=false;
            PIE4bits.U1RXIE=1;
        }
    }
    return;
}

void oscillatorInit(void)
{
    //オシレータ設定----------------
    OSCCON3bits.CSWHOLD=1;//Hold
    OSCCON1bits.NDIV=1;//64Mhz/2=32Mhz;
    while(!OSCCON3bits.NOSCR);
    while(!PIR0bits.CSWIF);//ready state
    PIR0bits.CSWIF=0;
    OSCCON3bits.CSWHOLD=0;
    while(!OSCCON3bits.ORDY);
}

void portInit(void)
{
    //ポート設定----------------------    
    PORTA=0x00;
    LATA=0x00;
    ANSELA=0x00;
    TRISA=0x80;
    
    PORTB=0x00;
    LATB=0x00;
    ANSELB=0x00;
    TRISB=0x00;
    
    PORTC=0x00;
    LATC=0x00;
    ANSELC=0x00;
    TRISC=0x00;
   
     //PPS---------------------
    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 0;
    
    //I2C1-------------------------
    //RC4 for SDA
    RC4PPS=0x38;
    I2C1SDAPPS=0x14;
    //RC3 for SCL
    RC3PPS = 0x37;
    I2C1SCLPPS=0x13;
    
    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 1;
    
    ODCONCbits.ODCC3=1;
    ODCONCbits.ODCC4=1;
    
    RC3I2Cbits.TH=1;
    RC4I2Cbits.TH=1;
    
}

void vicInit(void)
{
 //割り込みテーブルaddress設定----------------------------------
    INTCON0bits.GIE=0;//Enable all masked interrupts
    IVTLOCK=0x55;
    IVTLOCK=0xAA;
    IVTLOCKbits.IVTLOCKED=0;
    IVTBASE = 0x000008;
    IVTLOCK=0x55;
    IVTLOCK=0xAA;
    IVTLOCKbits.IVTLOCKED=1;
}

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?