SSD1306 OLED 驱动

前一阵子回家买了个 OLED (128 x 64,SSD1306)——Mini STM32 板的配件,这两天把驱动做完了,拿出来晾晾。


驱动是 pixel device 形式的。一开始本来打算做 frame buffer 形式的,但在测试时遇到了 hard fault 。俺怀疑是 RTGUI 的 frame buffer 驱动对单色显示的支持还不完善,但没有深究。
选用 pixel device 形式,也需要修改 RTGUI 代码以增加对单色显示的支持(”pixel_driver.c” and “color.h”)。
上图的 demo 使用新版 RTGUI,显示了一个 window,window 里有一个 label,没用 container。另外还显示了一张 bmp 图。图本身是单色的,加载时大小缩至 1/8。

和 LCD 对比一下, :) 。


再发点牢骚,新版 RTGUI 似乎在显示更新上有效率问题。比如上图的 demo ,有三个 window。按说每个 window 应该只绘制一次,但实际上似乎每个都绘制了三次。
现象:demo 中,背景的 main window 里面有个 container。在处理绘制 container 的 RTGUI_EVENT_PAINT 事件时,加载了一张图。最终,此图被加载了三次。
对于要加载大图的程序来说,这基本是噩梦。俺记得旧版没有这个问题。当然,有可能是俺对新版还不了解、使用不当。以后再研究吧。


更新:

跟 grissiom 兄在 github 上讨教了一下。感觉重复绘制问题是由于俺对新版 API 不了解所导致的。旧版有 workbench 、 view 的概念;新版没有,但多了  application 。使得有些功能在新版中得到了简化,还有些似乎是重新组织了一下。

俺的 demo (可在 RT-Thread EFM32 分支的代码中找到)在旧版中大概是这样的结构:

app --|--> workbench1 --> view1 --> (child) lable1  
      |--> workbench2 --> view2 (load image when painting) --> (child) lable2 
      |--> win_hello + box --> (child) lable3
当移植到新版时,俺根据一些例程和猜测,把 demo 改成了这个样子:

app --|--> win_info --> (child) container1 --> (child) lable1 
      |--> win_main --> (child) container2 (load image when painting) --> (child) lable2 
      |--> win_hello + box --> (child) lable3
在和 grissiom 兄讨教之后,俺又改成了这样:
app --|--> win_info --> (child) lable1
      |--> win_main (load image when painting) --> (child) lable2
      |--> win_hello + box --> (child) lable3

现在就没有重复绘制的问题了。看来新版 API 确实在简化应用程序开发方面做了不少努力。但是控件分组的功能要咋实现呢?待俺以后再研究吧。
下面是代码:

drv_oled.c

/***************************************************************************//**
 * @file 	dev_oled.c
 * @brief 	OLED driver of RT-Thread RTOS for MiniSTM32
 * 	COPYRIGHT (C) 2012, RT-Thread Development Team
 * @author 	onelife
 * @version 1.0
 *******************************************************************************
 * @section License
 * The license and distribution terms for this file may be found in the file
 *  LICENSE in this distribution or at http://www.rt-thread.org/license/LICENSE
 *******************************************************************************
 * @section Change Logs
 * Date			Author		Notes
 * 2012-06-15	onelife		Initial creation for MiniSTM32
 ******************************************************************************/

/***************************************************************************//**
 * @addtogroup MiniSTM32
 * @{
 ******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "board.h"
#include "drv_oled.h"

#if defined(MINISTM32_USING_OLED)
#include <rtgui/rtgui.h>
#include <rtgui/driver.h>

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
#ifdef MINISTM32_OLED_DEBUG
#define oled_debug(format,args...)      rt_kprintf(format, ##args)
#else
#define oled_debug(format,args...)
#endif

/* Private function prototypes -----------------------------------------------*/
static void oled_setPixel(rtgui_color_t *c, int x, int y);
static void oled_getPixel(rtgui_color_t *c, int x, int y);
static void oled_drawHLine(rtgui_color_t *c, int x1, int x2, int y);
static void oled_drawVLine(rtgui_color_t *c, int x , int y1, int y2);
static void oled_drawRawHLine(rt_uint8_t *pixels, int x1, int x2, int y);

/* Private variables ---------------------------------------------------------*/
static struct rt_device oled_device;
struct rt_semaphore oled_lock;
static struct rt_device_graphic_info oled_info;
//static rt_uint8_t frame_buffer[MINISTM32_OLED_HEIGHT/8][MINISTM32_OLED_WIDTH];
static const struct rtgui_graphic_driver_ops oled_ops =
    {
        oled_setPixel,
        oled_getPixel,
        oled_drawHLine,
        oled_drawVLine,
        oled_drawRawHLine
    };

/* Private functions ---------------------------------------------------------*/
rt_inline void oled_delayUs(rt_uint32_t us)
{
    /* This function is not that accurate */
    rt_uint32_t i = SystemCoreClock / 1000000 * us / 3;

    for(; i > 0; i--);
}

rt_inline void ssd1306_writeByte(rt_uint8_t data)
{
    MINISTM32_OLED_DATA_OUT(data);
    MINISTM32_OLED_WR_RESET;
    MINISTM32_OLED_WR_SET;
}

rt_inline void ssd1306_readByte(rt_uint8_t *data)
{
    GPIOB->CRL = 0x88888888;
    GPIOB->ODR = (GPIOB->ODR & 0x0000FF00) | 0x000000FF;

    MINISTM32_OLED_RD_RESET;
    MINISTM32_OLED_DATA_IN(data);
    MINISTM32_OLED_RD_SET;

	GPIOB->CRL = 0x33333333;
    GPIOB->ODR = (GPIOB->ODR & 0x0000FF00) | 0x000000FF;
}

rt_inline void ssd1306_readBuffer(rt_uint8_t *data, rt_uint8_t size)
{
    rt_uint8_t i;

    GPIOB->CRL = 0x88888888;
    GPIOB->ODR = (GPIOB->ODR & 0x0000FF00) | 0x000000FF;

    for (i = 0; i < size; i++)
    {
        MINISTM32_OLED_RD_RESET;
        MINISTM32_OLED_DATA_IN(data++);
        MINISTM32_OLED_RD_SET;
    }

	GPIOB->CRL = 0x33333333;
    GPIOB->ODR = (GPIOB->ODR & 0x0000FF00) | 0x000000FF;
}

static void oled_writeCmd(rt_uint8_t data)
{
    MINISTM32_OLED_CS_RESET;
    MINISTM32_OLED_DC_RESET;
    ssd1306_writeByte(data);
    MINISTM32_OLED_DC_SET;
    MINISTM32_OLED_CS_SET;
}

static void oled_writeLongCmd(rt_uint8_t *data, rt_uint8_t size)
{
    rt_uint8_t i;

    MINISTM32_OLED_CS_RESET;
    MINISTM32_OLED_DC_RESET;
    for (i = 0; i < size; i++)
    {
        ssd1306_writeByte(*data++);
    }
    MINISTM32_OLED_DC_SET;
    MINISTM32_OLED_CS_SET;
}

static void oled_writeData(rt_uint8_t *data, rt_uint8_t size)
{
    rt_uint8_t i;

    MINISTM32_OLED_CS_RESET;
    for (i = 0; i < size; i++)
    {
        ssd1306_writeByte(*data++);
    }
    MINISTM32_OLED_CS_SET;
}

static void oled_readStatus(rt_uint8_t *data)
{
    MINISTM32_OLED_CS_RESET;
    MINISTM32_OLED_DC_RESET;
    ssd1306_readByte(data);
    MINISTM32_OLED_DC_SET;
    MINISTM32_OLED_CS_SET;
}

static void oled_readData(rt_uint8_t *data, rt_uint8_t size)
{
    rt_uint8_t dummy;

    MINISTM32_OLED_CS_RESET;
    ssd1306_readByte(&dummy);
    ssd1306_readBuffer(data, size);
    MINISTM32_OLED_CS_SET;
}

void oled_clear(void)
{
	rt_uint32_t i;
    rt_uint8_t data[3];

    // Set column address
    data[0] = 0x21;
    data[1] = 0x00;
    data[2] = MINISTM32_OLED_WIDTH - 1;
    oled_writeLongCmd(data, 3);

    // Set page address
    data[0] = 0x22;
    data[1] = 0x00;
    data[2] = (MINISTM32_OLED_HEIGHT - 1) / 8;
    oled_writeLongCmd(data, 3);

    MINISTM32_OLED_CS_RESET;
	for (i = 0; i < (MINISTM32_OLED_WIDTH * (MINISTM32_OLED_HEIGHT / 8)); i++)
    {
        ssd1306_writeByte(0x00);
//        oled_delayUs(100);
	}
    MINISTM32_OLED_CS_SET;
}

static void ssd1306_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    /* Config GPIO */
    RCC_APB2PeriphClockCmd(MINISTM32_OLED_DATA_CLOCK | \
        MINISTM32_OLED_CTRL_CLOCK | RCC_APB2Periph_AFIO, ENABLE);
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin   = \
        GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | \
        GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_Init(MINISTM32_OLED_DATA_PORT, &GPIO_InitStructure);
    GPIO_Write(MINISTM32_OLED_DATA_PORT, GPIO_InitStructure.GPIO_Pin);

    GPIO_InitStructure.GPIO_Pin   = \
        MINISTM32_OLED_CS_PIN | MINISTM32_OLED_DC_PIN | \
        MINISTM32_OLED_WR_PIN | MINISTM32_OLED_RD_PIN;
    GPIO_Init(MINISTM32_OLED_CTRL_PORT, &GPIO_InitStructure);
    GPIO_Write(MINISTM32_OLED_CTRL_PORT, GPIO_InitStructure.GPIO_Pin);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
}

static rt_err_t ssd1306_init(void)
{
    rt_uint8_t data[2];

    ssd1306_gpio_init();

    // Turn off panel
    oled_writeCmd(0xAE);

    // Set display clock
    data[0] = 0xD5;
    data[1] = 0x80;         // default
    oled_writeLongCmd(data, 2);
    // Set charge pump
    data[0] = 0x8D;
    data[1] = 0x14;         // enable
    oled_writeLongCmd(data, 2);
    // Set pre-charge period
    data[0] = 0xD9;
    data[1] = 0xF1;
    oled_writeLongCmd(data, 2);
    // Set Vcomh deselect level
    data[0] = 0xDB;
    data[1] = 0x30;         // 0x83 x Vcc
    oled_writeLongCmd(data, 2);
    // Set contrast
    data[0] = 0x81;
    data[1] = 0xEF;
    oled_writeLongCmd(data, 2);

    // Set memory addressing mode
    data[0] = 0x20;
    data[1] = 0x00;         // horizontal mode
    oled_writeLongCmd(data, 2);
    // Set segment remap
    oled_writeCmd(0xA1);    // colume 127 -> SEG0
    // Set normal display
    oled_writeCmd(0xA6);
    // Set multiplex ratio
    data[0] = 0xA8;
    data[1] = 0x3f;         // N = 64, default
    oled_writeLongCmd(data, 2);
    // Set COM output scan direction
    oled_writeCmd(0xC8);    // from COM[N-1] to COM0
    // Set COM pin
    data[0] = 0xDA;
    data[1] = 0x12;         // alternative, disable left/right remap, default
    oled_writeLongCmd(data, 2);
    // Set display offset
    data[0] = 0xD3;
    data[1] = 0x00;         // default
    oled_writeLongCmd(data, 2);
    // Set low column address
//    oled_writeCmd(0x00);    // default
    // Set high column address
//    oled_writeCmd(0x10);    // default
    // Set display start line
    oled_writeCmd(0x40);    // default

    // Turn on display
    oled_writeCmd(0xA4);
    // Turn on panel
    oled_writeCmd(0xAF);

    oled_clear();

    return RT_EOK;
}

/***************************************************************************//**
 * @brief
 *   Get the color of a pixel
 *
 * @details
 *
 * @note
 *
 * @param[out] c
 *  Pointer to color
 *
 * @param[in] x
 *  Horizontal position
 *
 * @param[in] y
 *  Vertical position
 ******************************************************************************/
static void oled_getPixel(rtgui_color_t *c, int x, int y)
{
    rt_err_t ret;
    rt_uint8_t color, data[3];

    if ((x >= MINISTM32_OLED_WIDTH) || (y >= MINISTM32_OLED_HEIGHT))
    {
        return;
    }

    if (rt_hw_interrupt_check())
    {
        ret = rt_sem_take(&oled_lock, RT_WAITING_NO);
    }
    else
    {
        ret = rt_sem_take(&oled_lock, RT_WAITING_FOREVER);
    }
    if (ret != RT_EOK)
    {
        return;
    }

    // Set column address
    data[0] = 0x21;
    data[1] = x;
    data[2] = x;
    oled_writeLongCmd(data, 3);

    // Set page address
    data[0] = 0x22;
    data[1] = y / 8;
    data[2] = y / 8;
    oled_writeLongCmd(data, 3);

    oled_readData(&color, 1);
    if (color & (1 << (y % 8)))
    {
        *(rt_uint8_t *)c = 0x01;
    }
    else
    {
        *(rt_uint8_t *)c = 0x00;
    }

    rt_sem_release(&oled_lock);
}

/***************************************************************************//**
 * @brief
 *   Draw a pixel with specified color
 *
 * @details
 *
 * @note
 *
 * @param[in] c
 *  Pointer to color
 *
 * @param[in] x
 *  Horizontal position
 *
 * @param[in] y
 *  Vertical position
 ******************************************************************************/
static void oled_setPixel(rtgui_color_t *c, int x, int y)
{
    rt_err_t ret;
    rt_uint8_t color, data[3];

    if ((x >= MINISTM32_OLED_WIDTH) || (y >= MINISTM32_OLED_HEIGHT))
    {
        return;
    }

    if (rt_hw_interrupt_check())
    {
        ret = rt_sem_take(&oled_lock, RT_WAITING_NO);
    }
    else
    {
        ret = rt_sem_take(&oled_lock, RT_WAITING_FOREVER);
    }
    if (ret != RT_EOK)
    {
        return;
    }

    // Set column address
    data[0] = 0x21;
    data[1] = x;
    data[2] = x;
    oled_writeLongCmd(data, 3);

    // Set page address
    data[0] = 0x22;
    data[1] = y / 8;
    data[2] = y / 8;
    oled_writeLongCmd(data, 3);

    oled_readData(&color, 1);
    color &= ~(1 << (y % 8));
    if (*(rt_uint8_t *)c)
    {
        color |= 1 << (y % 8);
    }
    oled_writeData(&color, 1);

    rt_sem_release(&oled_lock);
}

/***************************************************************************//**
 * @brief
 *   Draw a horizontal line with raw color
 *
 * @details
 *
 * @note
 *
 * @param[in] pixels
 *  Pointer to raw color
 *
 * @param[in] x1
 *  Horizontal start position
 *
 * @param[in] x2
 *  Horizontal end position
 *
 * @param[in] y
 *  Vertical position
 ******************************************************************************/
static void oled_drawRawHLine(rt_uint8_t *pixels, int x1, int x2, int y)
{
    rt_err_t ret;
    rt_uint8_t color[MINISTM32_OLED_WIDTH], data[3];
    rt_uint32_t i;

    if ((x1 >= MINISTM32_OLED_WIDTH) || (y >= MINISTM32_OLED_HEIGHT))
    {
        return;
    }
    if (x2 >= MINISTM32_OLED_WIDTH)
    {
        x2 = MINISTM32_OLED_WIDTH - 1;
    }

    if (rt_hw_interrupt_check())
    {
        ret = rt_sem_take(&oled_lock, RT_WAITING_NO);
    }
    else
    {
        ret = rt_sem_take(&oled_lock, RT_WAITING_FOREVER);
    }
    if (ret != RT_EOK)
    {
        return;
    }

    // Set column address
    data[0] = 0x21;
    data[1] = x1;
    data[2] = x2;
    oled_writeLongCmd(data, 3);

    // Set page address
    data[0] = 0x22;
    data[1] = y / 8;
    data[2] = y / 8;
    oled_writeLongCmd(data, 3);

    oled_readData(color, x2 - x1 + 1);
    for (i = 0; i < x2 - x1; i++)
    {
        color[i] &= ~(1 << (y % 8));
        if (*pixels++)
        {
            color[i] |= 1 << (y % 8);
        }
    }
    oled_writeData(color, x2 - x1 + 1);

    rt_sem_release(&oled_lock);
    oled_debug("rawH (%d-%d, %d) %x\n", x1, x2, y, *pixels);
}

/***************************************************************************//**
 * @brief
 *   Draw a horizontal line with specified color
 *
 * @details
 *
 * @note
 *
 * @param[in] c
 *  Pointer to color
 *
 * @param[in] x1
 *  Horizontal start position
 *
 * @param[in] x2
 *  Horizontal end position
 *
 * @param[in] y
 *  Vertical position
 ******************************************************************************/
static void oled_drawHLine(rtgui_color_t *c, int x1, int x2, int y)
{
    rt_err_t ret;
    rt_uint8_t color[MINISTM32_OLED_WIDTH], data[3];
    rt_uint32_t i;

    if ((x1 >= MINISTM32_OLED_WIDTH) || (y >= MINISTM32_OLED_HEIGHT))
    {
        return;
    }
    if (x2 >= MINISTM32_OLED_WIDTH)
    {
        x2 = MINISTM32_OLED_WIDTH - 1;
    }

    if (rt_hw_interrupt_check())
    {
        ret = rt_sem_take(&oled_lock, RT_WAITING_NO);
    }
    else
    {
        ret = rt_sem_take(&oled_lock, RT_WAITING_FOREVER);
    }
    if (ret != RT_EOK)
    {
        return;
    }

    // Set column address
    data[0] = 0x21;
    data[1] = x1;
    data[2] = x2;
    oled_writeLongCmd(data, 3);

    // Set page address
    data[0] = 0x22;
    data[1] = y / 8;
    data[2] = y / 8;
    oled_writeLongCmd(data, 3);

    oled_readData(color, x2 - x1 + 1);
    for (i = 0; i < x2 - x1; i++)
    {
        color[i] &= ~(1 << (y % 8));
    }
    if (*(rt_uint8_t *)c)
    {
        for (i = 0; i < x2 - x1; i++)
        {
            color[i] |= 1 << (y % 8);
        }
    }
    oled_writeData(color, x2 - x1 + 1);

    rt_sem_release(&oled_lock);
}

/***************************************************************************//**
 * @brief
 *   Draw a vertical line with specified color
 *
 * @details
 *
 * @note
 *
 * @param[in] c
 *  Pointer to color
 *
 * @param[in] x
 *  Horizontal position
 *
 * @param[in] y1
 *  Vertical start position
 *
 * @param[in] y2
 *  Vertical end position
 ******************************************************************************/
static void oled_drawVLine(rtgui_color_t *c, int x , int y1, int y2)
{
    rt_err_t ret;
    rt_uint8_t color[MINISTM32_OLED_HEIGHT], data[3];
    rt_uint32_t i;

    if ((x >= MINISTM32_OLED_WIDTH) || (y1 >= MINISTM32_OLED_HEIGHT))
    {
        return;
    }
    if (y2 >= MINISTM32_OLED_HEIGHT)
    {
        y2 = MINISTM32_OLED_HEIGHT - 1;
    }

    if (rt_hw_interrupt_check())
    {
        ret = rt_sem_take(&oled_lock, RT_WAITING_NO);
    }
    else
    {
        ret = rt_sem_take(&oled_lock, RT_WAITING_FOREVER);
    }
    if (ret != RT_EOK)
    {
        return;
    }

    // Set memory addressing mode
    data[0] = 0x20;
    data[1] = 0x01;         // vertical mode
    oled_writeLongCmd(data, 2);

    // Set column address
    data[0] = 0x21;
    data[1] = x;
    data[2] = x;
    oled_writeLongCmd(data, 3);

    // Set page address
    data[0] = 0x22;
    data[1] = y1 / 8;
    data[2] = y2 / 8;
    oled_writeLongCmd(data, 3);

    oled_readData(color, (y2 - y1 + 1 + 7) / 8);
    if (*(rt_uint8_t *)c)
    {
        for (i = y1; i <= y2; i++)
        {
            color[i / 8] |= 1 << (i % 8);
        }
    }
    else
    {
        for (i = y1; i <= y2; i++)
        {
            color[i / 8] &= ~(1 << (i % 8));
        }
    }
    oled_writeData(color, (y2 - y1 + 1 + 7) / 8);

    // Set memory addressing mode
    data[0] = 0x20;
    data[1] = 0x00;         // horizontal mode
    oled_writeLongCmd(data, 2);

    rt_sem_release(&oled_lock);
    oled_debug(" VLine (%d, %d-%d) %x\n", x, y1, y2, *(rt_uint8_t *)c);
}

/***************************************************************************//**
 * @brief
 *   Open OLED device
 *
 * @details
 *
 * @note
 *
 * @param[in] dev
 *   Pointer to device descriptor
 *
 * @param[in] oflag
 *   Device open flag
 *
 * @return
 *   Error code
 ******************************************************************************/
static rt_err_t miniStm32_oled_open(rt_device_t dev, rt_uint16_t oflag)
{
    return RT_EOK;
}

/***************************************************************************//**
 * @brief
 *   Close OLED device
 *
 * @details
 *
 * @note
 *
 * @param[in] dev
 *   Pointer to device descriptor
 *
 * @return
 *   Error code
 ******************************************************************************/
static rt_err_t miniStm32_oled_close(rt_device_t dev)
{
    return RT_EOK;
}

/*static void miniStm32_oled_update(struct rt_device_rect_info *rect)
{
    rt_uint8_t i, data[3];

    if ((rect->x >= MINISTM32_OLED_WIDTH) || (rect->y >= MINISTM32_OLED_HEIGHT))
    {
        return;
    }

    // Set column address
    data[0] = 0x21;
    data[1] = rect->x;
    if ((rect->x + rect->width) >= MINISTM32_OLED_WIDTH)
    {
        data[2] = MINISTM32_OLED_WIDTH - 1;
    }
    else
    {
        data[2] = rect->x + rect->width;
    }
    oled_writeLongCmd(data, 3);

    // Set page address
    data[0] = 0x22;
    data[1] = rect->y / 8;
    if ((rect->y + rect->height) >= MINISTM32_OLED_HEIGHT)
    {
        data[2] = (MINISTM32_OLED_HEIGHT - 1) / 8;
    }
    else
    {
        data[2] = (rect->y + rect->height) / 8;
    }
    oled_writeLongCmd(data, 3);

    for (i = data[1]; i <= data[2]; i++)
    {
        oled_writeData(&frame_buffer[i][rect->x], rect->width);
    }
}*/

/***************************************************************************//**
* @brief
*   Configure OLED device
*
* @details
*
* @note
*
* @param[in] dev
*   Pointer to device descriptor
*
* @param[in] cmd
*   IIC control command
*
* @param[in] args
*   Arguments
*
* @return
*   Error code
******************************************************************************/
static rt_err_t miniStm32_oled_control(rt_device_t dev, rt_uint8_t cmd, void *args)
{
	switch (cmd)
	{
	case RTGRAPHIC_CTRL_RECT_UPDATE:
//        miniStm32_oled_update((struct rt_device_rect_info *)args);
        oled_debug("OLED: update\n");
		break;
	case RTGRAPHIC_CTRL_POWERON:
		break;
	case RTGRAPHIC_CTRL_POWEROFF:
		break;
	case RTGRAPHIC_CTRL_GET_INFO:
		rt_memcpy(args, &oled_info, sizeof(oled_info));
		break;
	case RTGRAPHIC_CTRL_SET_MODE:
		break;
	}

	return RT_EOK;
}

/***************************************************************************//**
 * @brief
 *	Register OLED device
 *
 * @details
 *
 * @note
 *
 * @param[in] device
 *	Pointer to device descriptor
 *
 * @param[in] name
 *	Device name
 *
 * @param[in] flag
 *	Configuration flags
 *
 * @param[in] iic
 *	Pointer to IIC device descriptor
 *
 * @return
 *	Error code
 ******************************************************************************/
static rt_err_t miniStm32_oled_register(
	rt_device_t	        device,
	const char          *name,
	rt_uint32_t         flag,
	void                *data)
{
	RT_ASSERT(device != RT_NULL);

	device->type 		= RT_Device_Class_Graphic;
	device->rx_indicate = RT_NULL;
	device->tx_complete = RT_NULL;
	device->init 		= RT_NULL;
	device->open		= miniStm32_oled_open;
	device->close		= miniStm32_oled_close;
	device->read 		= RT_NULL;
	device->write 		= RT_NULL;
	device->control 	= miniStm32_oled_control;
	device->user_data	= data;

	/* register a character device */
	return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | flag);
}

/***************************************************************************//**
 * @brief
 *   Initialize OLED device
 *
 * @details
 *
 * @note
 *
 ******************************************************************************/
void miniStm32_hw_oled_init(void)
{
    rt_uint32_t flag;
    rt_uint8_t status;

    do
    {
        /* Init OLED info */
        flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE; //RT_DEVICE_FLAG_DMA_TX
        oled_info.pixel_format      = RTGRAPHIC_PIXEL_FORMAT_MONO;
        oled_info.bits_per_pixel    = 1;
        oled_info.width             = MINISTM32_OLED_WIDTH;
        oled_info.height            = MINISTM32_OLED_HEIGHT;
        oled_info.framebuffer       = RT_NULL; //(rt_uint8_t *)frame_buffer;
//        if (miniStm32_oled_register(&oled_device, OLED_DEVICE_NAME, flag, RT_NULL) != RT_EOK)
        if (miniStm32_oled_register(&oled_device, OLED_DEVICE_NAME, flag,
            (void *)&oled_ops) != RT_EOK)
        {
            break;
        }

        /* Init OLED lock */
        if (rt_sem_init(&oled_lock, OLED_DEVICE_NAME, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
        {
            break;
        }

        /* Init ssd1306 */
        if (ssd1306_init() != RT_EOK)
        {
            break;
        }

        oled_readStatus(&status);
        oled_debug("OLED: status %x\n", status);

        /* Set as rtgui graphic driver */
        if (rtgui_graphic_set_device(&oled_device) != RT_EOK)
        {
            break;
        }

        oled_debug("OLED: H/W init OK!\n");
        return;
    } while(0);

    oled_debug("OLED err: H/W init failed!\n");
}

#endif /* defined(MINISTM32_USING_OLED) */
/***************************************************************************//**
 * @}
 ******************************************************************************/

drv_oled.h

/***************************************************************************//**
 * @file 	dev_oled.h
 * @brief 	OLED driver of RT-Thread RTOS for MiniSTM32
 * 	COPYRIGHT (C) 2012, RT-Thread Development Team
 * @author 	onelife
 * @version 1.0
 *******************************************************************************
 * @section License
 * The license and distribution terms for this file may be found in the file
 *  LICENSE in this distribution or at http://www.rt-thread.org/license/LICENSE
 *******************************************************************************
 * @section Change Logs
 * Date			Author		Notes
 * 2012-06-15	onelife		Initial creation for MiniSTM32
 ******************************************************************************/
#ifndef __DEV_OLED_H__
#define __DEV_OLED_H__

/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
#define MINISTM32_OLED_WIDTH            (128)   /* Screen Width (in pixels) */
#define MINISTM32_OLED_HEIGHT           (64)    /* Screen Hight (in pixels) */

#define MINISTM32_OLED_CTRL_SUSPEND     (0x00)
#define MINISTM32_OLED_CTRL_RESUME      (0x01)

#define	MINISTM32_OLED_DATA_IN(data)    (*(data) = GPIOB->IDR & 0x000000FF)
#define	MINISTM32_OLED_DATA_OUT(data)   (GPIOB->ODR = (GPIOB->ODR & 0xFFFFFF00) | data)
#define	MINISTM32_OLED_CS_SET           (GPIOC->BSRR = GPIO_Pin_9)
#define	MINISTM32_OLED_DC_SET           (GPIOC->BSRR = GPIO_Pin_8)
#define	MINISTM32_OLED_WR_SET           (GPIOC->BSRR = GPIO_Pin_7)
#define	MINISTM32_OLED_RD_SET           (GPIOC->BSRR = GPIO_Pin_6)
#define	MINISTM32_OLED_CS_RESET         (GPIOC->BRR = GPIO_Pin_9)
#define	MINISTM32_OLED_DC_RESET         (GPIOC->BRR = GPIO_Pin_8)
#define	MINISTM32_OLED_WR_RESET         (GPIOC->BRR = GPIO_Pin_7)
#define	MINISTM32_OLED_RD_RESET         (GPIOC->BRR = GPIO_Pin_6)

#define	MINISTM32_OLED_DATA_CLOCK       (RCC_APB2Periph_GPIOB)
#define	MINISTM32_OLED_CTRL_CLOCK       (RCC_APB2Periph_GPIOC)
#define	MINISTM32_OLED_DATA_PORT        (GPIOB)
#define	MINISTM32_OLED_CTRL_PORT        (GPIOC)
#define	MINISTM32_OLED_CS_PIN           (GPIO_Pin_9)
#define	MINISTM32_OLED_DC_PIN           (GPIO_Pin_8)
#define	MINISTM32_OLED_WR_PIN           (GPIO_Pin_7)
#define	MINISTM32_OLED_RD_PIN           (GPIO_Pin_6)

/* Exported functions ------------------------------------------------------- */
void miniStm32_hw_oled_init(void);

#endif /* __DEV_OLED_H__ */

pixel_driver.c (修改部分)

static void _pixel_mono_set_pixel(rtgui_color_t *c, int x, int y)
{
	rt_uint8_t pixel;

	pixel = rtgui_color_to_mono(*c);
	gfx_device_ops->set_pixel((char*)&pixel, x, y);
}

static void _pixel_mono_get_pixel(rtgui_color_t *c, int x, int y)
{
	rt_uint8_t pixel;

	gfx_device_ops->get_pixel((char*)&pixel, x, y);
	*c = rtgui_color_from_mono(pixel);
}

static void _pixel_mono_draw_hline(rtgui_color_t *c, int x1, int x2, int y)
{
	rt_uint8_t pixel;

	pixel = rtgui_color_to_mono(*c);
	gfx_device_ops->draw_hline((char*)&pixel, x1, x2, y);
}

static void _pixel_mono_draw_vline(rtgui_color_t *c, int x, int y1, int y2)
{
	rt_uint8_t pixel;

	pixel = rtgui_color_to_mono(*c);
	gfx_device_ops->draw_vline((char*)&pixel, x, y1, y2);
}

static void _pixel_draw_raw_hline(rt_uint8_t *pixels, int x1, int x2, int y)
{
	gfx_device_ops->blit_line((char*)pixels, x1, x2, y);
}

const struct rtgui_graphic_driver_ops _pixel_mono_ops =
{
	_pixel_mono_set_pixel,
	_pixel_mono_get_pixel,
	_pixel_mono_draw_hline,
	_pixel_mono_draw_vline,
	_pixel_draw_raw_hline,
};

const struct rtgui_graphic_driver_ops *rtgui_pixel_device_get_ops(int pixel_format)
{
	switch (pixel_format)
	{
    case RTGRAPHIC_PIXEL_FORMAT_MONO:
        return &_pixel_mono_ops;

	case RTGRAPHIC_PIXEL_FORMAT_RGB565:
		return &_pixel_rgb565_ops;

	case RTGRAPHIC_PIXEL_FORMAT_RGB565P:
		return &_pixel_rgb565p_ops;

	case RTGRAPHIC_PIXEL_FORMAT_RGB888:
		return &_pixel_rgb888_ops;
	}

	return RT_NULL;
}

color.h (修改部分)

/* convert rtgui color to mono */
rt_inline rt_uint8_t rtgui_color_to_mono(rtgui_color_t c)
{
	rt_uint8_t pixel;

	pixel = (RTGUI_RGB_R(c) | RTGUI_RGB_G(c) | RTGUI_RGB_B(c)) ? 0x01 : 0x00;
	return pixel;
}

rt_inline rtgui_color_t rtgui_color_from_mono(rt_uint8_t pixel)
{
	rtgui_color_t color;

	if (pixel)
	{
    	color = white;
	}
    else
    {
        color = black;
    }
	return color;
}

文章转自: http://piao.sg/onelife/?p=213#comment-8


                
  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: Arduino SSD1306 OLED显示屏是一种基于Arduino开发板的显示屏,采用SSD1306驱动芯片,具有高亮度、低功耗、高对比度等特点。它可以用于显示各种信息,如文本、图像、图标等,适用于各种Arduino项目。 ### 回答2: Arduino SSD1306 OLED显示屏是一块高分辨率的单色显示屏,非常适合DIY电子爱好者在自己的项目中使用。与传统的LCD显示屏不同,OLED显示屏具有更快的响应速度、更低的功耗和更高的对比度,同时消耗的电力也更少,在相同的亮度下更加节能,因此在需要使用电池供电的项目中得到广泛应用。Arduino SSD1306 OLED显示屏由OLED屏幕、驱动IC、电容、电阻和其他一些辅助器件组成,通过I2C总线与Arduino板通信。 为了控制这块显示屏,我们需要一个专门编写的程序。在这个程序中,我们可以定义需要显示的内容,包括文本、图形、图标和图像。可以通过设置显示屏坐标和颜色来创建自定义的显示内容。可以使用不同的字体、大小和样式来创建独特的设计。 使用Arduino SSD1306 OLED显示屏的优点不只是它的高效能和易用性,还在于其开放性和扩展性。用户可以使用不同的软件库和驱动程序来创建自己的创新项目,或者使用可用的库和例子来快速上手。对于那些不熟悉编程的用户,也可以使用现成的图形库来轻松地创建复杂的图形和界面。 总的来说,Arduino SSD1306 OLED显示屏是一款多功能的单色显示屏,其灵活性和高效能使其成为DIY电子爱好者的首选。适用于各种类型的项目,包括智能家居、传感器网络、机器人、万花筒、数据可视化和可穿戴设备。 ### 回答3: Arduino ssd1306 oled显示屏是一种非常常见和实用的显示屏,其特点是高亮度、高对比度、低功耗、反应速度快等。这种显示屏采用SSD1306控制芯片,可以通过I2C接口与Arduino连接。SSD1306控制芯片集成了控制器和驱动器,可以通过软件控制屏幕内容。 要使用Arduino ssd1306 oled显示屏,首先需要下载并安装相应的库。在Arduino IDE中打开菜单“工具”-“库管理器”,搜索SSD1306并下载“Adafruit SSD1306”或者“U8g2”库。接下来,连接Arduino ssd1306 oled显示屏到Arduino板上,将VCC连接到5V,GND连接到GND,SDA连接到SDA,SCL连接到SCL。在Arduino IDE中选择正确的板子和端口,并打开一个新的示例程序。如果已安装了U8g2库,可以在示例中找到ssd1306的例子程序进行测试。 在程序中,可以通过调用相应函数来控制显示屏上显示内容,例如显示文本、图形、动画等。可以设置屏幕分辨率、字体大小、对齐方式等缩放和定位属性。可以使用函数来绘制点、线、矩形、圆形、多边形等基本图形,也可以导入和显示位图和动画等多媒体内容。 总的来说,Arduino ssd1306 oled显示屏是一种非常实用和常用的显示屏,可以用于各种跟踪、监控、测量、控制等应用场景。通过简单的硬件和软件设计,可以快速、方便、高效地实现其功能。在今后的开发中,Arduino ssd1306 oled显示屏将会得到更广泛的应用和发展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值