幸福小强 发表于 2025-5-29 16:00

使用pic18f47q10驱动 ssd1306的OLED

用于在 PIC18F47Q10 微控制器上使用 I2C 连接 0.91 英寸 SSD1306 OLED 显示屏。
该示例初始化显示并演示基本的绘图功能,包括简单的像素动画。


/*
* File:   main.c
* Author: maxymsmal
*
* Created on April 9, 2025, 11:25 PM
*/

// Config bytes
#pragma config WDTE = OFF
#pragma config LVP = ON

#include <pic18.h>
#include <xc.h>
#include "i2c_hw.h"
#include "ssd1306_display.h"

#define _XTAL_FREQ 32000000UL

void hw_init(void);

void main(void)
{
hw_init();

__delay_ms(100);

LATEbits.LATE0 = 0;

ssd1306_InitDisplay();

LATEbits.LATE0 = 1;

__delay_ms(100);

while (1) {
    ssd1306_DemoAnimation();
    __delay_ms(1000);
}
}

void hw_init(void)
{
OSCCON1bits.NOSC = 0x6;
OSCFRQbits.FRQ3 = 0x08;
// OSCFRQ = 0x08;


ANSELBbits.ANSELB1 = 0;
ANSELBbits.ANSELB2 = 0;

TRISBbits.TRISB5 = 0;
TRISBbits.TRISB4 = 0;

TRISEbits.TRISE0 = 0;
TRISEbits.TRISE1 = 0;

LATEbits.LATE1 = 1;
LATEbits.LATE0 = 0;

WPUBbits.WPUB1 = 1;
WPUBbits.WPUB2 = 1;

SSP1CL**S = 0x09;
RB1PPS = 0x0F;

SSP1DATPPS = 0x0A;
RB2PPS = 0x10;

SSP1CON1bits.SSPM3 = 1; /// Clock = F_OSC / (4 * (SSP1ADD + 1))
LATEbits.LATE0 = 1;

SSP1ADD = 0x13;//0x9F;   // Set the boud rate devider
}

玛尼玛尼哄 发表于 2025-5-29 16:02

不错,下载附件,希望这个OLED的库能有用。

小灵通2018 发表于 2025-5-29 16:32

这是用IO模拟的还是用硬件的I2C?

小灵通2018 发表于 2025-5-29 16:33

好像是硬件的,看到配置相关的寄存器了。

小灵通2018 发表于 2025-5-29 16:35


#include <stdint.h>
#include <stddef.h>
#include <string.h>

#include "ssd1306_display.h"
#include "i2c_hw.h"
#include "ssd1306_font.h"

uint8_t buffer;

void ssd1306_InitDisplay(void)
{
ssd1306_WriteCommand(0xAE);
ssd1306_WriteCommand(0xD5);
ssd1306_WriteCommand(0x80);
ssd1306_WriteCommand(0xA8);
ssd1306_WriteCommand(0x1F);
ssd1306_WriteCommand(0xD3);
ssd1306_WriteCommand(0x00);
ssd1306_WriteCommand(0x40);
ssd1306_WriteCommand(0x8D);
ssd1306_WriteCommand(0x14);
ssd1306_WriteCommand(0x20);
ssd1306_WriteCommand(0x00);
ssd1306_WriteCommand(0xA1);
ssd1306_WriteCommand(0xC8);
ssd1306_WriteCommand(0xDA);
ssd1306_WriteCommand(0x02);
ssd1306_WriteCommand(0x81);
ssd1306_WriteCommand(0x8F);
ssd1306_WriteCommand(0xD9);
ssd1306_WriteCommand(0xF1);
ssd1306_WriteCommand(0xDB);
ssd1306_WriteCommand(0x40);
ssd1306_WriteCommand(0xA4);
ssd1306_WriteCommand(0xA6);
ssd1306_WriteCommand(0x2E);
ssd1306_WriteCommand(0xAF);

ssd1306_ClearDisplay();
ssd1306_SetDisplay();
}

void ssd1306_WriteCommand(uint8_t command)
{
I2C1_open();
I2C1_startCondition();

I2C1_sendData((SSD1306_I2C_ADDR << 1) & ~0x01);
if (I2C1_getAckstatBit())
{
    I2C1_stopCondition();
    I2C1_close();
}

I2C1_sendData(0x00);
if (I2C1_getAckstatBit())
{
    I2C1_stopCondition();
    I2C1_close();
}

I2C1_sendData(command);
}

void ssd1306_WriteData(uint8_t *data, size_t size)
{
I2C1_open();
I2C1_startCondition();

I2C1_sendData((SSD1306_I2C_ADDR << 1) & ~0x01);

if (I2C1_getAckstatBit()){
    I2C1_stopCondition();
    I2C1_close();
}

I2C1_sendData(0x40);
if (I2C1_getAckstatBit()) {
    I2C1_stopCondition();
    I2C1_close();
}

for (size_t i = 0; i < size; i++) {
    I2C1_sendData(data);

    if (I2C1_getAckstatBit()) {
      break;
    }
}
}

void ssd1306_SetDisplay(void)
{
for (uint8_t page = 0; page < (SSD1306_HEIGHT / 8); page++)
{
    ssd1306_WriteCommand(0xB0 + page);
    ssd1306_WriteCommand(0x00);
    ssd1306_WriteCommand(0x10);

    ssd1306_WriteData(&buffer, SSD1306_WIDTH);
}
}

void ssd1306_SetDisplay_Horisontal(void)
{
ssd1306_WriteCommand(0x20);               // Memory Addressing Mode
ssd1306_WriteCommand(0x00);               // Horizontal Addressing Mode

ssd1306_WriteCommand(0x21);               // column address
ssd1306_WriteCommand(0);                  // Start column
ssd1306_WriteCommand(SSD1306_WIDTH - 1);

ssd1306_WriteCommand(0x22); // Set page address
ssd1306_WriteCommand(0);    // Start page
ssd1306_WriteCommand((SSD1306_HEIGHT / 8) - 1); // End page

ssd1306_WriteData(buffer, SSD1306_WIDTH * (SSD1306_HEIGHT / 8));
}

void ssd1306_SetDisplay_Vertical(void)
{
ssd1306_WriteCommand(0x20);               // Memory Addressing Mode
ssd1306_WriteCommand(0x01);               // Vertical Addressing Mode
   
ssd1306_WriteCommand(0x21);               // column address
ssd1306_WriteCommand(0);                  // Start column
ssd1306_WriteCommand(SSD1306_WIDTH - 1);
   
ssd1306_WriteCommand(0x22); // Set page address
ssd1306_WriteCommand(0);    // Start page
ssd1306_WriteCommand((SSD1306_HEIGHT / 8) - 1); // End page

ssd1306_WriteData(buffer, SSD1306_WIDTH * (SSD1306_HEIGHT / 8));
}

void ssd1306_ClearDisplay(void)
{
memset(buffer, 0, sizeof(buffer));
}

void ssd1306_EnableDisplay(uint8_t state)
{
ssd1306_WriteCommand(state ? 0xAF : 0xAE);
}

void ssd1306_SetContrast(uint8_t value)
{
ssd1306_WriteCommand(0x81);
ssd1306_WriteCommand(value);
}

void ssd1306_SetInversionMode(uint8_t setInversion)
{
ssd1306_WriteCommand(setInversion ? 0xA7 : 0xA6);
}

void ssd1306_SetEntireMode(uint8_t state)
{
ssd1306_WriteCommand(state ? 0xA5 : 0xA4);
}

void ssd1306_SetPixel(int16_t x, int16_t y, uint8_t color)
{
if (x < 0 || x >= SSD1306_WIDTH || y < 0 || y >= SSD1306_HEIGHT)
    return;

uint16_t byteIndex = x + (y / 8) * SSD1306_WIDTH;
uint8_t bitMask = 1 << (y % 8);

if (color)
    buffer |= bitMask;
else
    buffer &= ~bitMask;
}

void ssd1306_SetCursor(uint8_t x, uint8_t y) {
ssd1306_WriteCommand(0x21); // Set column address
ssd1306_WriteCommand(x);    // Start column
ssd1306_WriteCommand(127);// End column

ssd1306_WriteCommand(0x22); // Set page address
ssd1306_WriteCommand(y);    // Start page
ssd1306_WriteCommand(0x07); // End page
}

void ssd1306_SetChar(char c) {
const uint8_t* charMap = _charASCIIMap;
uint8_t charBuffer;

if (c < 32 || c > 126) {
      c = '?';
}

for (int i = 0; i < 5; i++) {
    charBuffer = charMap;
}
charBuffer = 0x00;

ssd1306_WriteData(charBuffer, sizeof(charBuffer));
}

void ssd1306_PutString(const char* str) {
while (*str) {
    ssd1306_SetChar(*str++);
}
}

void ssd1306_DemoAnimation(void) {
ssd1306_ClearDisplay();

for (int i = 0; i < 120; i += 5)
{
    ssd1306_ClearDisplay();

    for (int x = i; x < i + 30 && x < 128; x++)
    {
      for (int y = 5; y < 25; y++)
      {
      ssd1306_SetPixel(x, y, 1);
      }
    }
      
    ssd1306_SetDisplay();
}

ssd1306_ClearDisplay();         
ssd1306_SetCursor(15, 0);
ssd1306_PutString("Hello, world!");
}

小明的同学 发表于 2025-5-29 18:49

学习一下驱动方法

wanduzi 发表于 2025-5-29 21:55

这些常用的模块驱动,是必须要掌握的。

暖心小太阳 发表于 2025-6-3 08:47

这个示例代码看起来很不错,你已经成功地将PIC18F47Q10与SSD1306 OLED显示屏通过I2C连接起来了。动画演示部分应该能很好地展示基本的绘图功能。
页: [1]
查看完整版本: 使用pic18f47q10驱动 ssd1306的OLED