打印
[PIC®/AVR®/dsPIC®产品]

使用pic18f47q10驱动 ssd1306的OLED

[复制链接]
160|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
幸福小强|  楼主 | 2025-5-29 16:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
用于在 PIC18F47Q10 微控制器上使用 I2C 连接 0.91 英寸 SSD1306 OLED 显示屏。
该示例初始化显示并演示基本的绘图功能,包括简单的像素动画。
pic18f47q10_ssd1306_example-main.zip (22.37 KB)

/*
* 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 | 只看该作者
好像是硬件的,看到配置相关的寄存器了。

使用特权

评论回复
5
小灵通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[SSD1306_WIDTH * (SSD1306_HEIGHT / 8)];

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[i]);

    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 * page], 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[byteIndex] |= bitMask;
  else
    buffer[byteIndex] &= ~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[c - 32];
  uint8_t charBuffer[6];
  
  if (c < 32 || c > 126) {
      c = '?';
  }
  
  for (int i = 0; i < 5; i++) {
    charBuffer[i] = charMap[i];
  }
  charBuffer[5] = 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!");
}

使用特权

评论回复
6
小明的同学| | 2025-5-29 18:49 | 只看该作者
学习一下驱动方法

使用特权

评论回复
7
wanduzi| | 2025-5-29 21:55 | 只看该作者
这些常用的模块驱动,是必须要掌握的。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

132

主题

1632

帖子

2

粉丝