PICとRPI4Bのuartシリアル通信  1. lcd

[前回](https://qiita.com/retro_C18_4B/items/e224f302d4185a82fcc5)に続き、PIC18とRPI4Bのuart通信です。今回は、PIC18にｷｬﾗｸﾀｰlcdを追加して、RPI4Bより受信した文字列を表示します。4bitパラレル接続のSC1602BSです。I2Cのlcdが使い勝手がいいのですが、今回はこちらを使います。
PICのｷｬﾗｸﾀｰlcdで、RPI4Bより"Hello PIC Im Pi.Hello PIC Im Pi." を受信していたことが確認できました。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970076/7116fb64-ba55-0dce-36c8-34cfddab36f5.png)

配線図です。ｷｬﾗｸﾀｰlcdを追加しただけで、他は[前回](https://qiita.com/retro_C18_4B/items/e224f302d4185a82fcc5)と同じです。ｷｬﾗｸﾀｰlcdは、ｻﾌﾞ基板に分けています（下図）。
![subboard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970076/c272a093-f7ae-4ea1-ce56-74d392afc7d6.png)

RPI4B側のPythonプログラムは、前回と同じものを使います。
``` Python
#RPI-0-uart-tx.py
#Serial Console OFF, Serial ON
#RPI4B Buster(x32) Python 3.7.3 (x32) Thonny, and RUN  or 
#RPI4B bookworm(x64) Python 3.11.2 Thonny, and RUN

import serial

#Open SERIALttyS0
SERIALttyS0 = serial.Serial('/dev/ttyS0', 2304000, timeout=1)

#Set SendMessage
SendMessage = "Hello PIC Im Pi.Hello PIC Im Pi."
#Send Command
SERIALttyS0.write(SendMessage.encode())

#Receive ReturnMessage and print
binary_ReturnMessage = SERIALttyS0.readline()
ReturnMessage = binary_ReturnMessage.decode()
print(ReturnMessage)

#Close SERIALttyS0
SERIALttyS0.close()
```

PIC側のプログラムは、ｷｬﾗｸﾀｰlcdが増えています。PIC側のプログラムは、今回も、xc8とC18のプログラムです。PIC18のXC8プログラムです。
```
//main.c MPLAB X IDE v6.00, XC8 Compiler v2.4.0, (C90),  PICkit3
#include <xc.h>
#define _XTAL_FREQ 36864000 
#define LED_A0			LATA0
#define lcd_B7			LATB7
#define lcd_B6			LATB6
#define lcd_B5			LATB5
#define lcd_B4			LATB4
#define lcd_stb_E		LATA1
#define lcd_rs			LATA2
#define FXMA_CS0_TRIS	TRISC0
#define FXMA_CS0_IO		LATC0

//2620
#pragma config OSC = HSPLL
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRT = ON
#pragma config BOREN = OFF
#pragma config BORV = 3
#pragma config WDT = OFF
#pragma config WDTPS = 32768
#pragma config CCP2MX = PORTBE
#pragma config PBADEN = OFF
#pragma config LPT1OSC = OFF
#pragma config MCLRE = ON
#pragma config STVREN = OFF
#pragma config LVP = OFF
#pragma config XINST = OFF
#pragma config CP0 = OFF
#pragma config CP1 = OFF
#pragma config CP2 = OFF
#pragma config CP3 = OFF
#pragma config CPB = OFF
#pragma config CPD = OFF
#pragma config WRT0 = OFF
#pragma config WRT1 = OFF
#pragma config WRT2 = OFF
#pragma config WRT3 = OFF
#pragma config WRTC = OFF
#pragma config WRTB = OFF
#pragma config WRTD = OFF
#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF
#pragma config EBTR2 = OFF
#pragma config EBTR3 = OFF
#pragma config EBTRB = OFF

////26k22
//#pragma config FOSC = HSHP
//#pragma config PLLCFG = ON
//#pragma config PRICLKEN = ON
//#pragma config FCMEN = OFF
//#pragma config IESO = OFF
//#pragma config PWRTEN = ON
//#pragma config BOREN = OFF
//#pragma config BORV = 190
//#pragma config WDTEN = OFF
//#pragma config WDTPS = 32768
//#pragma config CCP2MX = PORTC1
//#pragma config PBADEN = OFF
//#pragma config CCP3MX = PORTB5
//#pragma config HFOFST = OFF
//#pragma config T3CMX = PORTC0
//#pragma config P2BMX = PORTB5
//#pragma config MCLRE = EXTMCLR
//#pragma config STVREN = OFF
//#pragma config LVP = OFF
//#pragma config XINST = OFF
//#pragma config CP0 = OFF
//#pragma config CP1 = OFF
//#pragma config CP2 = OFF
//#pragma config CP3 = OFF
//#pragma config CPB = OFF
//#pragma config CPD = OFF
//#pragma config WRT0 = OFF
//#pragma config WRT1 = OFF
//#pragma config WRT2 = OFF
//#pragma config WRT3 = OFF
//#pragma config WRTC = OFF
//#pragma config WRTB = OFF
//#pragma config WRTD = OFF
//#pragma config EBTR0 = OFF
//#pragma config EBTR1 = OFF
//#pragma config EBTR2 = OFF
//#pragma config EBTR3 = OFF
//#pragma config EBTRB = OFF

static unsigned char vBANK01[256];
static unsigned char vBuffer[32];
near unsigned char Temp1, data, data0, cmd;
near uint8_t i;
near uint16_t Wi, Wi_last;
near uint32_t Di;

//   lcd functions
void LCD__vBuffer32(void);
void LCD__Data(unsigned char data);
void LCD__Command(unsigned char cmd);
void LCD__Command_Upper(unsigned char cmd);
void LCD__Init(void);
void LCD__Clear(void);
void PUT_DATA(void);
void PUT_CMD(void);

void main()
{
    //2620
    ADCON0 = 0x00;
    ADCON1 = 0x0F;
    ////26k22
    //ANSELA = 0b00100000 ;		// AN4(RA5)
    //ANSELB = 0b00000000 ;
    //ANSELC = 0b00000000 ;

    TRISA  = 0b00100000 ;		// RA5
    TRISB  = 0b00000000 ;
    TRISC  = 0b00000000 ;
    PORTA  = 0b00000000 ;
    PORTB  = 0b00000000 ;
    PORTC  = 0b00000000 ;

    TRISC = 0x90;
    TXSTA = 0x24;
    RCSTA = 0x90;
    BAUDCON = 0x00;	
    SPBRG = 0x00;

    // lcd init
    LCD__Init();
    LCD__Command(0x01);
    LCD__Command(0x0c);

    Temp1=0x30;    
    for(i = 0; i < 32; i++)        
    {
        vBANK01[i]=Temp1;
        Temp1++;
    }
    for(i = 0; i < 32; i++)
    {
        vBuffer[i]=vBANK01[i];    
    }
    LCD__vBuffer32();
    __delay_ms(1000);

    FXMA_CS0_TRIS =0;
    FXMA_CS0_IO=0;
    Wi=0;
    Wi_last=31;
    for(; ; )
    {
        if (RCSTAbits.OERR)
        {
            RCSTAbits.CREN = 0;
            Temp1 = RCREG;
            RCSTAbits.CREN = 1;
        }
        if(RCIF==1) 
        {
            vBANK01[Wi]  = RCREG;
            Wi++;
        }
        if(Wi>Wi_last) {  break;  }
   }

    vBuffer[0] =0x48;  // H
    vBuffer[1] =0x45;  // E
    vBuffer[2] =0x4C;  // L
    vBuffer[3] =0x4C;  // L
    vBuffer[4] =0x4F;  // O
    vBuffer[5] =0x20;  // 
    vBuffer[6] =0x50;  // P
    vBuffer[7] =0x69;  // i
    vBuffer[8] =0x20;  // 
    vBuffer[9] =0x49;  // I
    vBuffer[10]=0x6D;  // m
    vBuffer[11]=0x20;  // 
    vBuffer[12]=0x50;  // P
    vBuffer[13]=0x49;  // I
    vBuffer[14]=0x43;  // C
    vBuffer[15]=0x40;  // @
    vBuffer[16]=0x0A;  // LF
    Wi=0;
    Wi_last=17;
    for(; ; )
    {
        //2620
        if(TRMT==1)
        ////26k22
        //if(TXSTAbits.TRMT==1) 
        {
            TXREG  =  vBuffer[Wi];
            Wi++;
        }
        if(Wi>Wi_last) {  break;  }
    }
    FXMA_CS0_IO=1;

    for(i = 0; i < 32; i++)
    {
        vBuffer[i]=vBANK01[i]; 
    }
    LCD__vBuffer32();
    __delay_ms(250) ;

    while(1) {
        LED_A0 = 0;
        __delay_ms(250) ;
        LED_A0 = 1;
        __delay_ms(250) ;
     }
}

//  SC1602BS lcd functios  //
void LCD__vBuffer32(void)
{
	uint8_t ii;
	LCD__Clear();
	for(ii = 0; ii < 16; ii++){
		data= vBuffer[ii];
		LCD__Data(data);
	}
	LCD__Command(0xC0);
	for(ii = 16; ii < 32; ii++){
		data= vBuffer[ii];
		LCD__Data(data);
	}
}

void LCD__Data(unsigned char data)
{
	uint8_t jj;
	for(jj=0; jj<=1; jj++)
	{
		if (jj==0)
			data0=data;
		else
			data0=data<<4;
		lcd_B7 = 0;
		lcd_B6 = 0;
		lcd_B5 = 0;
		lcd_B4 = 0;
		if((data0 & 0x80) != 0)
			lcd_B7 = 1;
		if((data0 & 0x40) != 0)
			lcd_B6 = 1;
		if((data0 & 0x20) != 0)
			lcd_B5 = 1;
		if((data0 & 0x10) != 0)
			lcd_B4 = 1;
		PUT_DATA();
	}
	__delay_us(50);
}

void LCD__Command(unsigned char cmd)
{
	uint8_t jj;
	for(jj=0; jj<=1; jj++)
	{
		if (jj==0)
			data0=cmd;
		else
			data0=cmd<<4;
		lcd_B7 = 0;
		lcd_B6 = 0;
		lcd_B5 = 0;
		lcd_B4 = 0;
		if((data0 & 0x80) != 0)
			lcd_B7 = 1;
		if((data0 & 0x40) != 0)
			lcd_B6 = 1;
		if((data0 & 0x20) != 0)
			lcd_B5 = 1;
		if((data0 & 0x10) != 0)
			lcd_B4 = 1;
		PUT_CMD();
	}
	__delay_us(50);
}

void LCD__Command_Upper(unsigned char cmd)
{
	lcd_B7 = 0;
	lcd_B6 = 0;
	lcd_B5 = 0;
	lcd_B4 = 0;
	if((data0 & 0x80) != 0)
		lcd_B7 = 1;
	if((data0 & 0x40) != 0)
		lcd_B6 = 1;
	if((data0 & 0x20) != 0)
		lcd_B5 = 1;
	if((data0 & 0x10) != 0)
		lcd_B4 = 1;
	PUT_CMD();
	__delay_ms(5);
}

void LCD__Clear(void)
{
	LCD__Command(0x01);
	__delay_ms(250);
}

void LCD__Init(void)
{
	__delay_ms(50);
	LCD__Command_Upper(0x30);
	LCD__Command_Upper(0x30);
	LCD__Command_Upper(0x30);
	LCD__Command_Upper(0x20);
	LCD__Command(0x2E);
	LCD__Command(0x08);
	LCD__Command(0x0D);
	LCD__Command(0x06);
    
	LCD__Clear();
}

void PUT_CMD(void)
{
	lcd_rs  = 0;
	_delay(1);
	lcd_stb_E = 1;
	_delay(4);
	lcd_stb_E = 0;
}

void PUT_DATA(void)
{
	lcd_rs  = 1;
	_delay(1);

	lcd_stb_E = 1;
	_delay(4);
	lcd_stb_E = 0;
}
```

PIC18のC18プログラムです。
```
// MainDemo.c MPLAB_IDE_8_92, MPLAB_C18_3.46,  PICkit3
#include <p18f2620.h>
//#include <p18f26k22.h>
#include <HardwareProfile.h>
#include <GenericTypeDefs.h>
#include <delays.h>

#pragma udata bank1  = 0x100
static unsigned char vBANK01[256];
#pragma udata bank2 = 0x200
static unsigned char vBuffer[32];

#pragma udata access my_access
near unsigned char Temp1, Temp2;
near BYTE i, j, k, ii, jj, kk;
near WORD Wi, Wj, Wk;
near DWORD Di, Dj, Dk;

//   lcd function
void LCD__Data(void);
void LCD__vBuffer32(void);
void LCD__Command(void);
void LCD__Clear(void);
void LCD__Init(void);
void PUT_CMD(void);
void PUT_DATA(void);

//   wait time
void TIME50(void);
void TIME5M(void);

#pragma code
void main(void){
	//2620
	ADCON0 = 0x00;
	ADCON1 = 0x0F;
	////26k22
	//ANSELA = 0b00100000 ;		// AN4(RA5)
	//ANSELB = 0b00000000 ;
	//ANSELC = 0b00000000 ;

	TRISA  = 0b00100000 ;		// RA5
	TRISB  = 0b00000000 ;
	TRISC  = 0b00000000 ;
	PORTA  = 0b00000000 ;
	PORTB  = 0b00000000 ;
	PORTC  = 0b00000000 ;

	TRISC = 0x90;
	TXSTA = 0x24;
	RCSTA = 0x90;
	BAUDCON = 0x00;	
	SPBRG = 0x00;

	// lcd init
	LCD__Init();
															
	Temp1=0x41;
	for(i = 0; i < 32; i++)		
	{
		vBANK01[i]=Temp1;	
		_asm  INCF  Temp1, 1, 0  _endasm
	}
	for(i = 0; i < 32; i++)
	{
		vBuffer[i]=vBANK01[i];	
	}
	LCD__vBuffer32();
	Delay10KTCYx(250);
	Delay10KTCYx(250);
	Delay10KTCYx(250);
	Delay10KTCYx(250);

	LED0_IO = 0;

	FXMA_CS0_TRIS = 0;
	FXMA_CS0_IO = 0;

	for(Wi = 0; Wi < 32; Wi++)
	{
 		if (RCSTAbits.OERR) 
		{
			RCSTAbits.CREN = 0;
			Temp1 = RCREG;
			RCSTAbits.CREN = 1;
		}
		_asm BTFSS  PIR1, 5, 0 	_endasm      // RCIF in P1R1 = 5
		_asm BRA -2	       		_endasm
		vBANK01[Wi]  = RCREG;
	}

	vBuffer[0] =0x48;  // H
	vBuffer[1] =0x45;  // E
	vBuffer[2] =0x4C;  // L
	vBuffer[3] =0x4C;  // L
	vBuffer[4] =0x4F;  // O
	vBuffer[5] =0x20;  // 
	vBuffer[6] =0x50;  // P
	vBuffer[7] =0x69;  // i
	vBuffer[8] =0x20;  // 
	vBuffer[9] =0x49;  // I
	vBuffer[10]=0x6D;  // m
	vBuffer[11]=0x20;  // 
	vBuffer[12]=0x50;  // P
	vBuffer[13]=0x49;  // I
	vBuffer[14]=0x43;  // C
	vBuffer[15]=0x40;  // @
	vBuffer[16]=0x0A;  // LF
	for(i = 0; i < 18; i++)		
	{
		_asm BTFSS TXSTA, 1, 0 _endasm      // TRMT in TXSTA = 1
		_asm BRA   -2	       _endasm
		TXREG  =  vBuffer[i];
	}

	FXMA_CS0_IO = 1;

	for(i = 0; i < 32; i++)		
	{
		vBuffer[i]=vBANK01[i];	
	}
	LCD__vBuffer32();
	Delay10KTCYx(250);

	while(1){
		LED0_IO = 0;
		Delay10KTCYx(250);
		LED0_IO = 1;
		Delay10KTCYx(250);
	}
}

// lcd functions
void LCD__Data(void)
{			
	//_asm MOVLB 	0		_endasm
	_asm MOVWF Temp1, 0 	_endasm
	_asm MOVLW 0x0F			_endasm
	_asm ANDWF PORTB, 1, 0 	_endasm
	_asm MOVF  Temp1, 0, 0 	_endasm
	_asm ANDLW 0xF0 		_endasm
	_asm IORWF PORTB, 1, 0 	_endasm
	PUT_DATA();
	_asm MOVLW 0x0F 		_endasm
	_asm ANDWF PORTB, 1, 0 	_endasm
	_asm SWAPF Temp1, 0, 0  _endasm
	_asm ANDLW 0xF0 		_endasm
	_asm IORWF PORTB, 1, 0 	_endasm
	PUT_DATA();
	TIME50();
}

void LCD__vBuffer32(void)
{
	LCD__Clear();
	for(kk = 0; kk < 16; kk++)		
	{
		Temp1= vBuffer[kk];
		LCD__Data();
	}
	_asm MOVLW 0xC0  	_endasm	
	LCD__Command();			
	TIME50();
	for(kk = 16; kk < 32; kk++)		
	{
		Temp1= vBuffer[kk];
		LCD__Data();
	}
}

void PUT_CMD(void)
{	
	lcd_rs  = 0;
	Nop();
	lcd_stb = 1;
	Nop();				
	Nop();
	Nop();				
	Nop();	
	lcd_stb = 0;
}

void PUT_DATA(void)
{
	lcd_rs  = 1;
	Nop();
	lcd_stb = 1;
	Nop();				
	Nop();
	Nop();				
	Nop();	
	lcd_stb = 0;
}

void LCD__Command(void)
{						
	_asm MOVWF Temp1, 0 	_endasm		
	_asm MOVLW 0x0F 		_endasm		
	_asm ANDWF PORTB, 1, 0 	_endasm		
	_asm MOVF  Temp1, 0, 0 	_endasm		
	_asm ANDLW 0xF0 		_endasm		
	_asm IORWF PORTB, 1, 0 	_endasm		
	PUT_CMD();
	_asm MOVLW 0x0F 		_endasm
	_asm ANDWF PORTB, 1, 0 	_endasm		
	_asm SWAPF Temp1, 0, 0  _endasm		
	_asm ANDLW 0xF0 		_endasm
	_asm IORWF PORTB, 1, 0 	_endasm		
	PUT_CMD();
	TIME50();				
}

void LCD__Clear(void)
{
	_asm MOVLW 0x01  	_endasm
	LCD__Command();	
	Delay10KTCYx(125);
	Delay10KTCYx(125);
}

void LCD__Init(void)
{	
	TIME5M();
	TIME5M();
	TIME5M();
	TIME5M();
	TIME5M();
	TIME5M();
	TIME5M();
	_asm MOVLW	0x0F	 		_endasm
	_asm ANDWF	PORTB,    1, 0 	_endasm
	_asm MOVLW	0x30			_endasm
	_asm IORWF	PORTB,    1, 0 	_endasm
	PUT_CMD();
	TIME5M();
	PUT_CMD();
	TIME5M();
	PUT_CMD();
	TIME5M();
	_asm MOVLW	0x0F	 		_endasm
	_asm ANDWF	PORTB,    1, 0 	_endasm	
	_asm MOVLW	0x20	 		_endasm
	_asm IORWF	PORTB,    1, 0 	_endasm
	PUT_CMD();
	TIME5M();
	_asm MOVLW 0x2E  		_endasm	
	LCD__Command();	
	_asm MOVLW 0x08 		_endasm
	LCD__Command();	
	_asm MOVLW 0x0D  		_endasm
	LCD__Command();	
	_asm MOVLW 0x06  		_endasm
	LCD__Command();	
	LCD__Clear();
}

//  about 50usec at 40MHz
void TIME50(void)
{
	_asm MOVLW	0x63		_endasm
	_asm MOVWF	ii, 0		_endasm 
	_asm NOP				_endasm
	_asm NOP				_endasm
	_asm DECFSZ	ii, 1, 0	_endasm	
	_asm BRA	-4			_endasm
}

//  about 5msec at 40MHz
void TIME5M(void)
{
	_asm MOVLW	0x64		_endasm
	_asm MOVWF	jj, 0		_endasm
	TIME50();
	_asm DECFSZ	jj, 1, 0	_endasm
	_asm BRA	-3			_endasm
}
```

C18用のHardwareProfile.hです。
```
// HardwareProfile.h MPLAB_IDE_8_92, MPLAB_C18_3.46
#ifndef __HARDWARE_PROFILE_H
#define __HARDWARE_PROFILE_H
// Clock frequency value.  This value is used to calculate Tick Counter value
	#define GetSystemClock()		(36864000ul)			// 9.216MHz  Crystal,  PLL x4
	#define GetInstructionClock()	(GetSystemClock()/4)
	#define GetPeripheralClock()	GetInstructionClock()
//  IO pins
	#define 	LED0_TRIS			(TRISAbits.TRISA0)
	#define 	LED0_IO				(LATAbits.LATA0)
	#define 	FXMA_CS0_TRIS		(TRISCbits.TRISC0)
	#define 	FXMA_CS0_IO			(LATCbits.LATC0)
//  lcd
	#define		lcd_port			(LATB)
	#define 	lcd_stb 			(LATAbits.LATA1)	// E
	#define 	lcd_rs  			(LATAbits.LATA2)
	//#define   lcd_w 
#endif

```
C18用のConfiguration Bitsは、[前回](https://qiita.com/retro_C18_4B/items/e224f302d4185a82fcc5)と同じです。

次回は、RPI4Bより、連続的に大量に受信した時に備えて、SPI-SRAMをPIC18に追加します。前に楽曲のMP3ファイルを再生する時に使ったものを流用します。