8686
@8686

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

PIC16F15325 SSD1306 I2C表示試験

解決したいこと

PIC16F15325でSSD1306に何か表示したい。通信はI2C。

MPLABを使用して以下のプログラムを作成しましたが、なにも表示されません。
解決方法を教えて下さい。

設定は
MCC Classic
Device ResourcesからMSSP1追加 interrupt driven:off serial:I2C, mode:Master clock:100kHz
Foundation ServiceからI2CSIMPLE追加 select I2C master: MSSP1
Interrupt Module MSSP BCLI: on, MSSP SSPI: on, Pin Module : off
System Module Oscillator Select:HFINTOSC, Ext Clock Select: not enable, HF Internal Clock: 32MHz, Clock Divider: 1, WDT Enable: WDT Disabled

プログラムmain.cは以下の通りです。

#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/examples/i2c1_master_example.h"

#define _XTAL_FREQ 32000000 // 32MHz

#define SSD1306_ADDR 0x78 // SSD1306 I2C address
#define SSD1306_CMD 0x00 // Command mode
#define SSD1306_DATA 0x40 // Data mode

// SSD1306 initialization commands
const uint8_t SSD1306_InitSeq[] = {
0xAE, // Display OFF
0xD5, 0x80, // Set display clock divide ratio/oscillator frequency
0xA8, 0x3F, // Set multiplex ratio (height of display)
0xD3, 0x00, // Set display offset
0x40, // Set start line
0x8D, 0x14, // Charge pump
0x20, 0x00, // Memory addressing mode (horizontal addressing)
0xA0, // Segment remap
0xC0, // COM scan direction
0xDA, 0x12, // Set COM pins hardware configuration
0x81, 0x7F, // Set contrast control
0xD9, 0xF1, // Set pre-charge period
0xDB, 0x40, // Set VCOMH deselect level
0xA4, // Entire display ON
0xA6, // Normal display
0xAF // Display ON
};

// Function to send command to SSD1306
void SSD1306_SendCommand(uint8_t command) {
I2C1_WriteNBytes(SSD1306_ADDR, &command, 1);
}

// Function to send data to SSD1306
void SSD1306_SendData(uint8_t data) {
I2C1_WriteNBytes(SSD1306_ADDR, &data, 1);
}

// Function to initialize SSD1306
void SSD1306_Init(void) {
for (uint8_t i = 0; i < sizeof(SSD1306_InitSeq); i++) {
SSD1306_SendCommand(SSD1306_CMD); // Command mode
SSD1306_SendData(SSD1306_InitSeq[i]);
}
}

// Function to clear the display (all pixels off)
void SSD1306_Clear(void) {
for (uint8_t page = 0; page < 8; page++) {
SSD1306_SendCommand(0xB0 + page); // Set page address
SSD1306_SendCommand(0x00); // Set lower column address
SSD1306_SendCommand(0x10); // Set higher column address
for (uint8_t col = 0; col < 128; col++) {
SSD1306_SendData(0x00); // Clear the entire display
}
}
}

// Function to set the cursor to the beginning of the display
void SSD1306_SetCursor(uint8_t x, uint8_t y) {
SSD1306_SendCommand(0xB0 + y); // Set page address
SSD1306_SendCommand(0x00 + (x & 0x0F)); // Set lower column address
SSD1306_SendCommand(0x10 + ((x >> 4) & 0x0F)); // Set higher column address
}

// Function to draw a horizontal line at a specified position
void SSD1306_DrawHorizontalLine(uint8_t x_start, uint8_t y_page, uint8_t length) {
SSD1306_SetCursor(x_start, y_page); // Set start position
for (uint8_t i = 0; i < length; i++) {
SSD1306_SendData(0xFF); // Draw pixel (all pixels on for the line)
}
}

// Function to draw a vertical line at a specified position
void SSD1306_DrawVerticalLine(uint8_t x, uint8_t y_start, uint8_t length) {
for (uint8_t i = y_start; i < y_start + length; i++) {
SSD1306_SetCursor(x, i); // Set vertical position
SSD1306_SendData(0x01); // Draw a single pixel
}
}

// Function to draw a simple box (rectangular shape)
void SSD1306_DrawRectangle(uint8_t x_start, uint8_t y_start, uint8_t width, uint8_t height) {
// Draw the top and bottom horizontal lines
for (uint8_t x = x_start; x < x_start + width; x++) {
SSD1306_DrawHorizontalLine(x, y_start, 1); // Top line
SSD1306_DrawHorizontalLine(x, y_start + height - 1, 1); // Bottom line
}
// Draw the left and right vertical lines
SSD1306_DrawVerticalLine(x_start, y_start, height); // Left line
SSD1306_DrawVerticalLine(x_start + width - 1, y_start, height); // Right line
}

/*
Main application
*/
void main(void) {
// Initialize the device
SYSTEM_Initialize();
//
INTERRUPT_GlobalInterruptEnable();
//
INTERRUPT_PeripheralInterruptEnable();

// Initialize SSD1306 display
SSD1306_Init();
SSD1306_Clear();

// Draw a rectangle on the screen
SSD1306_DrawRectangle(10, 2, 50, 30);  // Position (10, 2), Size (50x30)

while (1) {
    // Main loop code (nothing to do in this case)
    __delay_ms(500);
}

}

自分で試したこと

アドレスを0x78,0x79,0x3c,0x3dに変更したが改善されません。

2

1Answer

こんにちは。回答させていただきます

デバイスアドレスは0x3cでおそらく正しいように思いました
(もし違うのであれば0x3dではないかと思います)

初期化処理において、複数のコマンドを一度に送るような変更を試してみてもよいのではないかと思いました
例えば、SSD1306_InitSeq[]の先頭にSSD1306_CMD(0x00)を追加して、全データを一度にI2C1_WriteNBytesで送るような形が考えられます
(コマンドではなくデータを送る場合であれば、先頭にSSD1306_DATA(0x40)を追加したデータを用意することとなります)

// SSD1306 initialization commands
const uint8_t SSD1306_InitSeq[] = {
    SSD1306_CMD, // <= 追加する
    0xAE, // Display OFF
    0xD5, 0x80, // Set display clock divide ratio/oscillator frequency
    0xA8, 0x3F, // Set multiplex ratio (height of display)
    0xD3, 0x00, // Set display offset
    //省略
};

// SSD1306に複数のコマンドやデータを一度に送信する処理の例
void SSD1306_SendCommandsOrData(uint8_t* commandsOrData, size_t len) {
    //2バイト以上のデータを送信対象とする
    if(len < 2)
    {
        //送信できない
        return;
    }

    //先頭データはSSD1306_CMDまたはSSD1306_DATAとする
    if((commandsOrData[0] != SSD1306_CMD) && (commandsOrData[0] != SSD1306_DATA)) {
        //送信できない
        return;
    }

    //送信処理
    I2C1_WriteNBytes(SSD1306_ADDR, commandsOrData, len);
}

1バイトだけのコマンドやデータを送る処理が必要であれば、I2C1_WriteNBytesを使用するほかに
I2C1_Write1ByteRegisterを呼び出すような方法もあるのではないかと思いました

// Function to send command to SSD1306
void SSD1306_SendCommand(uint8_t command) {
    I2C1_Write1ByteRegister(SSD1306_ADDR, SSD1306_CMD, command);
}

// Function to send data to SSD1306
void SSD1306_SendData(uint8_t data) {
    I2C1_Write1ByteRegister(SSD1306_ADDR, SSD1306_DATA, data);
}

0Like

Your answer might help someone💌