• OLED12864(SSD1306)驱动代码


    1. 准备工作介绍

    我所使用的是 0.96 寸,I2C 接口的 OLED 屏幕。这款屏幕所使用的驱动芯片是 SSD1306 ,关于这款 OLED 驱动芯片的详细介绍可以参考下面这篇文章的介绍。

    SSD1306(OLED驱动芯片介绍)

    硬件平台测试平台我使用的是 STM32F407ZGT6 芯片的开发板。开发板和 OLED 屏幕的硬件连接引脚如下:

    硬件平台连接描述:
        
    SSD1306(屏幕)    |STM32F4xx(开发板)    |DESCRIPTION
    VCC             |3.3V                |
    GND             |GND                 |
    SCL             |PB10                |Serial clock line
    SDA             |PB11                |Serial data line
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    关于 STM32F407 芯片 I2C 外设初始化相关的代码,直接使用 CubeMX 生成即可。

    下面关于OLED绘图显示的相关代码,是参考了国外一位大佬的github仓库的,链接如下:

    https://github.com/MaJerle/stm32f429

    2. OLED驱动代码

    我所使用的 OLED 屏幕是 I2C 接口的,首先需要把通过 I2C 接口发送数据给 SSD1306 的驱动代码写好,这样才好实现后面的显示功能的代码。

    使用 HAL 库驱动 SSD1306 的代码如下:

    /*
     * 函数作用    : 通过I2C接口发送一个字节数据给SSD1306
     * 参数  reg   : 发送数据之前,需要先发送一个字节数据用于区分发送的是命令还是数据。其中先发送0x00,表示发送命令;先发送0x40,表示发送数据
     * 参数  data  : 要发送的一字节数据
     * 返回值      : 无
     */
    static void SSD1306_I2C_Write(uint8_t reg, uint8_t data)
    {
        uint8_t tmp_array[2] = {reg, data};
        HAL_I2C_Master_Transmit(&hi2c2, SSD1306_I2C_ADDR, tmp_array, sizeof(tmp_array), 1);
    }
    
    static void SSD1306_Write_Cmd(uint8_t cmd)
    {
        SSD1306_I2C_Write(0x00, cmd);
    }
    
    static void SSD1306_Write_Data(uint8_t data)
    {
        SSD1306_I2C_Write(0x40, data);
    }
    
    static void SSD1306_Write_MultiData(uint8_t *data, uint16_t size)
    {
    	uint8_t tmp_array[SSD1306_WIDTH+1] = {0x40, 0};
    
        memcpy(&tmp_array[1], data, size);
    	
        HAL_I2C_Master_Transmit(&hi2c2, SSD1306_I2C_ADDR, tmp_array, sizeof(tmp_array), 10);
    }
    
    /* 打开显示 */
    void SSD1306_ON(void) 
    {
        SSD1306_Write_Cmd(0x8D);
        SSD1306_Write_Cmd(0x14);
        SSD1306_Write_Cmd(0xAF);
    }
    
    /* 关闭显示 */
    void SSD1306_OFF(void) 
    {
        SSD1306_Write_Cmd(0x8D);
        SSD1306_Write_Cmd(0x10);
        SSD1306_Write_Cmd(0xAE);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    3. OLED显示字符串代码

    3.1 OLED屏幕显示原理

    屏幕是由一个个的像素点构成的,要想让屏幕显示出内容,只要按照规律点亮屏幕像素点即可。

    所以,要想让 OLED 显示出文字或者绘图等功能,我们可以通过 I2C 接口不断发送要显示的数据给 SSD1306 驱动芯片即可。这种方法好处是可以节省 MCU 的内存,因为不用在MCU内部使用 RAM 建立一块显存,只是要显示什么内容,立即通过 I2C 接口发送数据过去即可。

    还有一种方式是,在 MCU 内部建立一块用于显示的缓存,之后我们要显示什么内存,先修改这块显存的数据,然后一次性的通过 I2C 接口把全部显示数据发送到 SSD1306 。这种方式不好的地方就是费内存,但是优势是可以一次性的吧显存数据全部发送到屏幕上显示。

    我下面写的代码,就是在 MCU 内部建立一个显存,以后要显示什么内容都操作这块内存了,然后一次性的把显存数据发送到 SSD1306。代码如下:

    /* SSD1306 width in pixels */
    #define SSD1306_WIDTH            128
    
    /* SSD1306 LCD height in pixels */
    #define SSD1306_HEIGHT           64
    
    /* SSD1306 data buffer */
    static uint8_t SSD1306_Buffer[SSD1306_WIDTH * SSD1306_HEIGHT / 8];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    0.96寸的OLED一共有 128x64 个像素点(128x64 bit),所以需要建立一块 1Kb 的内存用作显存使用。

    3.2 OLED初始化代码

    初始化相关代码看厂商提供的手册拿过来用就行。

    void SSD1306_Init(void) 
    {
        /* A little delay */
        HAL_Delay(100);
    
        /* Init LCD */
        SSD1306_Write_Cmd(0xAE); //display off
        SSD1306_Write_Cmd(0x20); //Set Memory Addressing Mode
        SSD1306_Write_Cmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
        SSD1306_Write_Cmd(0xB0); //Set Page Start Address for Page Addressing Mode,0-7
        SSD1306_Write_Cmd(0xC8); //Set COM Output Scan Direction
        SSD1306_Write_Cmd(0x00); //---set low column address
        SSD1306_Write_Cmd(0x10); //---set high column address
        SSD1306_Write_Cmd(0x40); //--set start line address
        SSD1306_Write_Cmd(0x81); //--set contrast control register
        SSD1306_Write_Cmd(0xFF);
        SSD1306_Write_Cmd(0xA1); //--set segment re-map 0 to 127
        SSD1306_Write_Cmd(0xA6); //--set normal display
        SSD1306_Write_Cmd(0xA8); //--set multiplex ratio(1 to 64)
        SSD1306_Write_Cmd(0x3F); //
        SSD1306_Write_Cmd(0xA4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
        SSD1306_Write_Cmd(0xD3); //-set display offset
        SSD1306_Write_Cmd(0x00); //-not offset
        SSD1306_Write_Cmd(0xD5); //--set display clock divide ratio/oscillator frequency
        SSD1306_Write_Cmd(0xF0); //--set divide ratio
        SSD1306_Write_Cmd(0xD9); //--set pre-charge period
        SSD1306_Write_Cmd(0x22); //
        SSD1306_Write_Cmd(0xDA); //--set com pins hardware configuration
        SSD1306_Write_Cmd(0x12);
        SSD1306_Write_Cmd(0xDB); //--set vcomh
        SSD1306_Write_Cmd(0x20); //0x20,0.77xVcc
        SSD1306_Write_Cmd(0x8D); //--set DC-DC enable
        SSD1306_Write_Cmd(0x14); //
        SSD1306_Write_Cmd(0xAF); //--turn on SSD1306 panel
    
        /* Clear screen */
        SSD1306_Fill(SSD1306_COLOR_BLACK);
    
        /* Update screen */
        SSD1306_UpdateScreen();
    
        /* Set default values */
        SSD1306.CurrentX = 0;
        SSD1306.CurrentY = 0;
    
        /* Initialized OK */
        SSD1306.Initialized = 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    3.3 操作显示缓冲区的几个重要函数

    /* 更新屏幕显示,当我们把显示缓冲区数据改写了之后,必须调用这个函数才能在屏幕更新显示 */
    void SSD1306_UpdateScreen(void) 
    {
        uint8_t page;
    
        for (page = 0; page < 8; page++) 
        {
            SSD1306_Write_Cmd(0xB0 + page);
            SSD1306_Write_Cmd(0x00);
            SSD1306_Write_Cmd(0x10);
    
            /* Write multi data */
            SSD1306_Write_MultiData(&SSD1306_Buffer[SSD1306_WIDTH * page], SSD1306_WIDTH);
        }
    }
    
    /* 反转屏幕显示(就是黑白颜色对调) */
    void SSD1306_ToggleInvert(void) 
    {
        uint16_t i;
    
        /* Toggle invert */
        SSD1306.Inverted = !SSD1306.Inverted;
    
        /* Do memory toggle */
        for (i = 0; i < sizeof(SSD1306_Buffer); i++) 
        {
            SSD1306_Buffer[i] = ~SSD1306_Buffer[i];
        }
    }
    
    /* 填充显存,比如让屏幕全部点亮或者熄灭 */
    void SSD1306_Fill(SSD1306_COLOR_t color) 
    {
        /* Set memory */
        memset(SSD1306_Buffer, (color == SSD1306_COLOR_BLACK) ? 0x00 : 0xFF, sizeof(SSD1306_Buffer));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    3.4 绘制任意像素点函数

    绘制任意点的像素函数,这是后面写的所有绘图函数的基础,后面的显示字符、画线、画圆、填充图案等等绘图函数都是基于这个绘制任意点函数的基础上的。

    /**
     * @brief  SSD1306 color enumeration
     */
    typedef enum {
        SSD1306_COLOR_BLACK = 0x00, /*!< Black color, no pixel */
        SSD1306_COLOR_WHITE = 0x01  /*!< Pixel is set. Color depends on LCD */
    } SSD1306_COLOR_t;
    
    void SSD1306_DrawPixel(uint16_t x, uint16_t y, SSD1306_COLOR_t color) 
    {
        if (x >= SSD1306_WIDTH || y >= SSD1306_HEIGHT) 
        {
            /* Error */
            return;
        }
    
        /* Check if pixels are inverted */
        if (SSD1306.Inverted) 
        {
            color = (SSD1306_COLOR_t)!color;
        }
    
        /* Set color */
        if (color == SSD1306_COLOR_WHITE) 
        {
            SSD1306_Buffer[x + (y / 8) * SSD1306_WIDTH] |= 1 << (y % 8);
        } 
        else 
        {
            SSD1306_Buffer[x + (y / 8) * SSD1306_WIDTH] &= ~(1 << (y % 8));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    3.5 在屏幕上显示一个字符

    要想在屏幕显示一个字符,需要有字体库。字体库的定义不同,对于显示字符的函数实现也是不一样的,如果用了其他的字体库定义,可能导致该函数并不能完成显示字符的功能。

    字体库这里使用一个结构体对字库进行封装起来,包括字库的宽高,还有指向字库数组的指针。

    /**
     * @brief  Font structure used on my LCD libraries
     */
    typedef struct {
        uint8_t FontWidth;    /*!< Font width in pixels */
        uint8_t FontHeight;   /*!< Font height in pixels */
        const uint16_t* data; /*!< Pointer to data font data array */
    } TM_FontDef_t;
    
    /*
     * 函数作用 : 在屏幕上显示一个字符
     * 参数  ch    : 要显示的字符
     * 参数  Font  : 字体
     * 参数  color : 颜色
     * 返回值 : 无
     */
    char SSD1306_Putc(char ch, TM_FontDef_t* Font, SSD1306_COLOR_t color) 
    {
        uint32_t i, b, j;
    
        /* Check available space in LCD */
        if (SSD1306_WIDTH <= (SSD1306.CurrentX + Font->FontWidth) ||
            SSD1306_HEIGHT <= (SSD1306.CurrentY + Font->FontHeight)) 
        {
            /* Error */
            return 0;
        }
    
        /* Go through font */
        for (i = 0; i < Font->FontHeight; i++) 
        {
            b = Font->data[(ch - 32) * Font->FontHeight + i];
            for (j = 0; j < Font->FontWidth; j++) 
            {
                if ((b << j) & 0x8000) 
                {
                    SSD1306_DrawPixel(SSD1306.CurrentX + j, (SSD1306.CurrentY + i), (SSD1306_COLOR_t) color);
                } 
                else 
                {
                    SSD1306_DrawPixel(SSD1306.CurrentX + j, (SSD1306.CurrentY + i), (SSD1306_COLOR_t)!color);
                }
            }
        }
    
        /* Increase pointer */
        SSD1306.CurrentX += Font->FontWidth;
    
        /* Return character written */
        return ch;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    3.6 显示字符串

    有了显示字符的函数,显示字符串就简单多了。

    char SSD1306_Puts(char* str, TM_FontDef_t* Font, SSD1306_COLOR_t color) 
    {
        /* Write characters */
        while (*str) 
        {
            /* Write character by character */
            if (SSD1306_Putc(*str, Font, color) != *str) {
                /* Return error */
                return *str;
            }
    
            /* Increase string pointer */
            str++;
        }
    
        /* Everything OK, zero should be returned */
        return *str;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4. OLED绘图相关代码

    绘图的实现,主要就是操作显存的数据,然后再把数据一次性的更新到屏幕上。这里绘图的代码主要实现了画点、任意线、四边形、三角形、圆形等。

    这部分的代码实现,都要依赖于前面实现的绘制任意点函数。

    4.1 绘制任意线

    /* 
     * 参数:x0, y0是起点坐标
     *      x1, y1是终点坐标
     *      c 是绘制的颜色 
     */
    void SSD1306_DrawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, SSD1306_COLOR_t c) 
    {
        int16_t dx, dy, sx, sy, err, e2, i, tmp;
    
        /* Check for overflow */
        if (x0 >= SSD1306_WIDTH) 
        {
            x0 = SSD1306_WIDTH - 1;
        }
        if (x1 >= SSD1306_WIDTH) 
        {
            x1 = SSD1306_WIDTH - 1;
        }
        if (y0 >= SSD1306_HEIGHT) 
        {
            y0 = SSD1306_HEIGHT - 1;
        }
        if (y1 >= SSD1306_HEIGHT) 
        {
            y1 = SSD1306_HEIGHT - 1;
        }
    
        dx = (x0 < x1) ? (x1 - x0) : (x0 - x1);
        dy = (y0 < y1) ? (y1 - y0) : (y0 - y1);
        sx = (x0 < x1) ? 1 : -1;
        sy = (y0 < y1) ? 1 : -1;
        err = ((dx > dy) ? dx : -dy) / 2;
    
        if (dx == 0) 
        {
            if (y1 < y0) 
            {
                tmp = y1;
                y1 = y0;
                y0 = tmp;
            }
    
            if (x1 < x0) 
            {
                tmp = x1;
                x1 = x0;
                x0 = tmp;
            }
    
            /* Vertical line */
            for (i = y0; i <= y1; i++) 
            {
                SSD1306_DrawPixel(x0, i, c);
            }
    
            /* Return from function */
            return;
        }
    
        if (dy == 0) 
        {
            if (y1 < y0) 
            {
                tmp = y1;
                y1 = y0;
                y0 = tmp;
            }
    
            if (x1 < x0) 
            {
                tmp = x1;
                x1 = x0;
                x0 = tmp;
            }
    
            /* Horizontal line */
            for (i = x0; i <= x1; i++) 
            {
                SSD1306_DrawPixel(i, y0, c);
            }
    
            /* Return from function */
            return;
        }
    
        while (1) 
        {
            SSD1306_DrawPixel(x0, y0, c);
            if (x0 == x1 && y0 == y1) 
            {
                break;
            }
            e2 = err;
            if (e2 > -dx) 
            {
                err -= dy;
                x0 += sx;
            }
            if (e2 < dy) 
            {
                err += dx;
                y0 += sy;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105

    4.2 绘制四边形

    void SSD1306_DrawRectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, SSD1306_COLOR_t c) 
    {
        /* Check input parameters */
        if (x >= SSD1306_WIDTH || y >= SSD1306_HEIGHT) 
        {
            /* Return error */
            return;
        }
    
        /* Check width and height */
        if ((x + w) >= SSD1306_WIDTH) 
        {
            w = SSD1306_WIDTH - x;
        }
        if ((y + h) >= SSD1306_HEIGHT) 
        {
            h = SSD1306_HEIGHT - y;
        }
    
        /* Draw 4 lines */
        SSD1306_DrawLine(x, y, x + w, y, c);         /* Top line */
        SSD1306_DrawLine(x, y + h, x + w, y + h, c); /* Bottom line */
        SSD1306_DrawLine(x, y, x, y + h, c);         /* Left line */
        SSD1306_DrawLine(x + w, y, x + w, y + h, c); /* Right line */
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    4.3 绘制三角形

    void SSD1306_DrawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, SSD1306_COLOR_t color) 
    {
        /* Draw lines */
        SSD1306_DrawLine(x1, y1, x2, y2, color);
        SSD1306_DrawLine(x2, y2, x3, y3, color);
        SSD1306_DrawLine(x3, y3, x1, y1, color);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.4 三角形填充

    void SSD1306_DrawFilledTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, SSD1306_COLOR_t color) 
    {
        int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
                yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0,
                curpixel = 0;
    
        deltax = ABS(x2 - x1);
        deltay = ABS(y2 - y1);
        x = x1;
        y = y1;
    
        if (x2 >= x1) 
        {
            xinc1 = 1;
            xinc2 = 1;
        } 
        else 
        {
            xinc1 = -1;
            xinc2 = -1;
        }
    
        if (y2 >= y1) 
        {
            yinc1 = 1;
            yinc2 = 1;
        } 
        else 
        {
            yinc1 = -1;
            yinc2 = -1;
        }
    
        if (deltax >= deltay) 
        {
            xinc1 = 0;
            yinc2 = 0;
            den = deltax;
            num = deltax / 2;
            numadd = deltay;
            numpixels = deltax;
        } 
        else 
        {
            xinc2 = 0;
            yinc1 = 0;
            den = deltay;
            num = deltay / 2;
            numadd = deltax;
            numpixels = deltay;
        }
    
        for (curpixel = 0; curpixel <= numpixels; curpixel++) 
        {
            SSD1306_DrawLine(x, y, x3, y3, color);
    
            num += numadd;
            if (num >= den) 
            {
                num -= den;
                x += xinc1;
                y += yinc1;
            }
            x += xinc2;
            y += yinc2;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    4.5 绘制圆形

    void SSD1306_DrawCircle(int16_t x0, int16_t y0, int16_t r, SSD1306_COLOR_t c) 
    {
        int16_t f = 1 - r;
        int16_t ddF_x = 1;
        int16_t ddF_y = -2 * r;
        int16_t x = 0;
        int16_t y = r;
    
        SSD1306_DrawPixel(x0, y0 + r, c);
        SSD1306_DrawPixel(x0, y0 - r, c);
        SSD1306_DrawPixel(x0 + r, y0, c);
        SSD1306_DrawPixel(x0 - r, y0, c);
    
        while (x < y) 
        {
            if (f >= 0) 
            {
                y--;
                ddF_y += 2;
                f += ddF_y;
            }
            x++;
            ddF_x += 2;
            f += ddF_x;
    
            SSD1306_DrawPixel(x0 + x, y0 + y, c);
            SSD1306_DrawPixel(x0 - x, y0 + y, c);
            SSD1306_DrawPixel(x0 + x, y0 - y, c);
            SSD1306_DrawPixel(x0 - x, y0 - y, c);
    
            SSD1306_DrawPixel(x0 + y, y0 + x, c);
            SSD1306_DrawPixel(x0 - y, y0 + x, c);
            SSD1306_DrawPixel(x0 + y, y0 - x, c);
            SSD1306_DrawPixel(x0 - y, y0 - x, c);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    4.6 圆形填充

    void SSD1306_DrawFilledCircle(int16_t x0, int16_t y0, int16_t r, SSD1306_COLOR_t c) 
    {
        int16_t f = 1 - r;
        int16_t ddF_x = 1;
        int16_t ddF_y = -2 * r;
        int16_t x = 0;
        int16_t y = r;
    
        SSD1306_DrawPixel(x0, y0 + r, c);
        SSD1306_DrawPixel(x0, y0 - r, c);
        SSD1306_DrawPixel(x0 + r, y0, c);
        SSD1306_DrawPixel(x0 - r, y0, c);
        SSD1306_DrawLine(x0 - r, y0, x0 + r, y0, c);
    
        while (x < y) 
        {
            if (f >= 0) 
            {
                y--;
                ddF_y += 2;
                f += ddF_y;
            }
            x++;
            ddF_x += 2;
            f += ddF_x;
    
            SSD1306_DrawLine(x0 - x, y0 + y, x0 + x, y0 + y, c);
            SSD1306_DrawLine(x0 + x, y0 - y, x0 - x, y0 - y, c);
    
            SSD1306_DrawLine(x0 + y, y0 + x, x0 - y, y0 + x, c);
            SSD1306_DrawLine(x0 + y, y0 - x, x0 - y, y0 - x, c);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    完整的工程源码我已经上传了CSDN,点击下面连接跳转下载:

    https://download.csdn.net/download/luobeihai/86501329

  • 相关阅读:
    java执行shell命令,Runtime.exec()和jsch谁更有优势?
    设计模型之六大原则(有的地方称之为七大原则)
    【黑马-SpringCloud技术栈】【11】分布式事务-Seata
    PCL 点云超体素分割
    机试:成绩排名
    python常见的面试题,看你都掌握了吗
    【C语言】字符与字符串---从入门到入土级详解
    python毕业设计作品基于django框架个人博客系统毕设成品(6)开题答辩PPT
    AKK菌——下一代有益菌
    CTF-PWN-tips
  • 原文地址:https://blog.csdn.net/luobeihai/article/details/126562719