8ピンなどの小さなマイコンでは使用するピン数が少ないUARTやI2Cなどのシリアル接続が便利です。
液晶キャラクタディスプレイも自作のモジュールでUART接続やI2C接続にしてきましたが,どうせなら両方に対応できるモジュールが便利かと思い,試しに作ってみました。
サンライク社の液晶キャラクタディスプレイSC1602BSLB(パラレル接続)に作ったモジュールを組み込み,Raspberry Pi PicoからUARTとI2Cの両方の接続でデータを送り表示しているところです。一応動いています(^^)。

・モジュールの構成
モジュールはUART接続として作っていたものにI2Cパートのハードとソフトを追加しました。ほぼATtiny404に配線してコネクタをつけた感じです(^^;;;;;;。
MPU:ATtiny404,3.3V動作
UART:Rxのみ使用,9600baud
UPDI:プログラミング用
I2C :SDA,SCL,Groveコネクタで接続
抵抗:I2C PULL UP 4.7KΩ,バックライト可変抵抗 20kΩ
コンデンサ:バイパスコンデンサ 104

・配線の概略とコマンドなど
データバスは4bitモードで使用しています。
モジュールの機能は「どこに何を書くか」に絞っています(^^)。

無理やりI2Cパートを追加したので,配線はより分かり難くなりました(^^;;;;,。

幾つか同じ構成で作っておこうかと思うのですが,,,ディスプレイの裏側はもっと余裕があるのでもう少し大きめの基板にしないといけませんね(^^)。
・プログラムのメモ
以下に1) モジュール と 2) 送信側のPicoのプログラム をメモしておきます。
1) モジュールのプログラム
特に割り込みなどは使わず,普通にデータを待っています。
2) 送信側Picoのプログラム
実際にはUARTとI2Cを同時に接続することはまず無いとは思いますが,I2Cの表示が乱れる事がまれにあります。
UART処理が終わるのをもう少し待ったほうが安定するのでしょうか,,,。
液晶キャラクタディスプレイも自作のモジュールでUART接続やI2C接続にしてきましたが,どうせなら両方に対応できるモジュールが便利かと思い,試しに作ってみました。
サンライク社の液晶キャラクタディスプレイSC1602BSLB(パラレル接続)に作ったモジュールを組み込み,Raspberry Pi PicoからUARTとI2Cの両方の接続でデータを送り表示しているところです。一応動いています(^^)。

・モジュールの構成
モジュールはUART接続として作っていたものにI2Cパートのハードとソフトを追加しました。ほぼATtiny404に配線してコネクタをつけた感じです(^^;;;;;;。
MPU:ATtiny404,3.3V動作
UART:Rxのみ使用,9600baud
UPDI:プログラミング用
I2C :SDA,SCL,Groveコネクタで接続
抵抗:I2C PULL UP 4.7KΩ,バックライト可変抵抗 20kΩ
コンデンサ:バイパスコンデンサ 104

・配線の概略とコマンドなど
データバスは4bitモードで使用しています。
モジュールの機能は「どこに何を書くか」に絞っています(^^)。

無理やりI2Cパートを追加したので,配線はより分かり難くなりました(^^;;;;,。

幾つか同じ構成で作っておこうかと思うのですが,,,ディスプレイの裏側はもっと余裕があるのでもう少し大きめの基板にしないといけませんね(^^)。
・プログラムのメモ
以下に1) モジュール と 2) 送信側のPicoのプログラム をメモしておきます。
1) モジュールのプログラム
特に割り込みなどは使わず,普通にデータを待っています。
/** LCD1602 Controll test Pro., ATtiny404 UART & I2C **/
// UART: 9600baud, Rx_Pin PB3
// I2C : Slave Address 5, SCL_Pin PB0, SDA_Pin PB1
// 4Bit Bus: A4-A7, Enable A2, Resistor Select A1
// LCD : HD44780 compatible, number of lines 1-4
#include <Wire.h>
#define DB7 A7
#define DB6 A6
#define DB5 A5
#define DB4 A4
#define _E A2
#define _RS A1
void setup() { /* Set Up */
pinMode(DB7, OUTPUT ); // Set Pins as output for 4bit Data Bus
pinMode(DB6, OUTPUT );
pinMode(DB5, OUTPUT );
pinMode(DB4, OUTPUT );
pinMode(_E, OUTPUT ); // Data Enable (Latch), High -> Low
pinMode(_RS, OUTPUT ); // Rgistor Select, 1:data / 0:command
delay (40); // Init. LCD (Power on Reset)
sendU4bit(0, 0x30); // Function Set 8bit mode #1
delayMicroseconds(37);
sendU4bit(0, 0x30); // Function Set 8bit mode #2
delayMicroseconds(37);
sendU4bit(0, 0x30); // Function Set 8bit mode #3
delayMicroseconds(37);
sendU4bit(0, 0x20); // Function Set 4bit mode
delayMicroseconds(37);
sendCommand(0x28); // 4bit mode & 2line=1, font=0
sendCommand(0x06); // Cursor move increment, Shift off
sendCommand(0x01); // Clear Display
sendCommand(0x0C); // Display On, Cursor off, Blink off
Serial.begin(9600); // Start UART 9600baud
Wire.begin(5); // Start I2C, Slave_Address=5
} // setup end
void loop() { /* main loop */
byte recieveData1,recieveData2;
recieveData1=getOnebyte(); // Recieve One Byte
if (recieveData1<0x04){ // if data < 4, it is Row_Number
recieveData2=getOnebyte(); // get next 1byte, Column Number
locate(recieveData1,recieveData2); // Set Locate
}else if (recieveData1>0x1F && recieveData1<0x80){ // if data is " >0x1F & <0x80"
sendDisplay(recieveData1); // Disp. Ascii
}else if (recieveData1==0x80){ // if data is 0x80
recieveData2=getOnebyte(); // get next 1byte(command)
sendCommand(recieveData2); // send command
}else if (recieveData1==0xC0){ // if data is 0xC0
recieveData2=getOnebyte(); // get next 1byte(charactor code)
sendDisplay(recieveData2); // Disp. charactor
}
} //loop end
byte getOnebyte(){ // get 1byte via UART or I2C
byte oneByte;
while (Serial.available() == 0 && Wire.available() == 0){} //waiting for data
if (Serial.available() > 0){
oneByte=Serial.read();
}else{
oneByte=Wire.read();
}
return oneByte;
}
void locate(byte rowNumber, byte columnNumber){
byte ddramAddress;
switch (rowNumber) {
case 0:
ddramAddress=0;
break;
case 1:
ddramAddress=0x40;
break;
case 2:
ddramAddress=0x14;
break;
case 3:
ddramAddress=0x54;
break;
}
ddramAddress=(ddramAddress+columnNumber) | 0x80;
sendCommand(ddramAddress);
}
void sendCommand(byte cdData){
send8bit(0, cdData); // Resistor Select =0
if (cdData < 4){ // if command is "clear display" or "Return Home"
delay(2); // wait 2ms
}else{ // else
delayMicroseconds(37); // wait 37us
}
}
void sendDisplay(byte cdData){
send8bit(1, cdData); // Resistor Select =1
delayMicroseconds(37); // wait 37us
}
void send8bit(byte RS, byte cdData){
sendU4bit(RS, cdData); // send Upper 4bit
sendU4bit(RS, cdData*16); // send (Lower 4bit *16)
}
void sendU4bit(byte RS, byte upper4bit){
digitalWrite(_RS, RS); // Registor Select
digitalWrite(_E, HIGH); // Set Enable High
digitalWrite(DB7, bitRead(upper4bit,7)); // Set 4bit data
digitalWrite(DB6, bitRead(upper4bit,6));
digitalWrite(DB5, bitRead(upper4bit,5));
digitalWrite(DB4, bitRead(upper4bit,4));
digitalWrite(_E, LOW); // Set Enable Low (Data Latch)
}
2) 送信側Picoのプログラム
実際にはUARTとI2Cを同時に接続することはまず無いとは思いますが,I2Cの表示が乱れる事がまれにあります。
UART処理が終わるのをもう少し待ったほうが安定するのでしょうか,,,。
// Pico Serial test for ATtiny404 UART & I2C module for LCD
// UART: Serial1, 9600baud, Tx_Pin 0 (default)
// I2C : 100kbps, SDA_Pin 4 SCL_Pin 5 (default)
#include <Wire.h>
const byte LCD_Address=5; // LCD I2c Slave_Address 5
const char* u_str="UART: "; // character strings
const char* i2c_str="I2C : ";
void Serial1_locate(byte row, byte column){ // Send cursor location via Serial1
Serial1.write(row);
Serial1.write(column);
}
void I2C_write(byte b1){ // Send 1byte via I2C
Wire.beginTransmission(LCD_Address);
Wire.write(b1);
Wire.endTransmission();
}
void I2C_locate(byte row, byte column){ // Send cursor location via I2C
Wire.beginTransmission(LCD_Address);
Wire.write(row);
Wire.write(column);
Wire.endTransmission();
}
void setup(){ /* setup */
Serial1.begin(9600); // Start Serial1 9600baud
Wire.begin() ; // Start I2C 100kbps (default)
delay(100); // Wait until LCD is ready (Power on Reset)
Serial1.write(0x80); // Clear display (command 0x01)
Serial1.write(0x01);
delay(2);
Serial1_locate(0,1); // disp. characters via Serial1
Serial1.print(u_str);
delay(100);
I2C_locate(1,1); // disp. characters via I2C
Wire.beginTransmission(LCD_Address);
Wire.write(i2c_str);
Wire.endTransmission();
} //setup end
void loop() {
// Increase the number from 0 to 100
for (int d_value=0; d_value<=100; d_value++){
Serial1_locate(0,7); // disp. d_value in 3 digits
uTx_digit3(d_value); // via Serial1
I2C_locate(1,7); // disp. (100-d_value ) in 3 digits
i2c_digit3(100-d_value);// via I2C
delay(1000); // wait 1sec.
}
} //loop end
void uTx_digit3(int disp_value){ // disp. value in 3 digits
Serial1.print(disp_value/100); // via Serial1
Serial1.print(disp_value%100/10);
Serial1.print(disp_value%10);
}
void i2c_digit3(int disp_value){ // disp. value in 3 digits
I2C_write(disp_value/100+0x30); // via I2C
I2C_write(disp_value%100/10+0x30);
I2C_write(disp_value%10+0x30);
}