STM32 HAL库F103系列之OLED显示一个字符

原理图:

OLED对应IO口

OLED_CS对应OV_WRST,即:PD6;

OLED_RS对应OV_SCL,即:PD3,高电平为命令,低电平为数据;

OLED_WR对应OV_RRST,即:PG14;

OLED_RD 对应DCMI_SDA,即:PG13;

OLED_RST对应DCMI_RESET,即:PG15;

OLED_D[7:0]对应DCMI_D[7:0],即:PC[7:0]

配置步骤:

1,确定IO连接关系

        开发板OLED接口原理图

2,初始化IO

        初始化连接OLED的各个IO

3,编写8080接口函数

        oled_wr_byte

4,编写OLED初始化函数

        编写oled_init函数,完成初始化序列配置

5,编写OLED画点函数

        编写oled_draw_point函数,实现OLED任意位置画点

oled.c函数编程步骤

1、建立OLED的GRAM

2、画点函数实现代码

3、16*16大小,字符A的点阵数据数组:

4、字符显示代码

5、初始化OLED(SSD1306)

6、SSD1306(8080时序)写时序

7、void oled_draw_point_test(uint8_t x, uint8_t y)函数

8、void oled_clear(void)函数

源码

oled.c

#include "stdlib.h"
#include "./BSP/OLED/oled.h"
#include "./BSP/OLED/oledfont.h"
#include "./SYSTEM/delay/delay.h"

//建立OLED的GRAM
static uint8_t g_oled_gram[128][8];

void oled_refresh_gram(void)
{
    uint8_t i,n;

    for (i = 0; i < 8; i++)
    {
        oled_wr_byte(0xb0 + i, OLED_CMD) ;  /* 设置页地址(0~7)*/
        oled_wr_byte(0x00, OLED_CMD) ;      /* 设置显示位置-列低地址 */ 
        oled_wr_byte(0x10, OLED_CMD) ;      /* 设置显示位置-列高地址 */
        
        for (n = 0; n < 128; n++)
        {
            oled_wr_byte( g_oled_gram[ n ][ i ], OLED_DATA) ;
        }
    }
}

//画点函数实现代码
void oled_draw_point(uint8_t  x, uint8_t  y, uint8_t  dot) 
{
    uint8_t pos, bx, temp = 0;
    
    if (x > 127 || y > 63)  return;    /* 超出范围了 */
    
    pos = y / 8;    /*  页地址 */
    bx = y % 8;     /*  计算y在对应字节里面的位置 */
    temp = 1 << bx; /*  转换后y对应的bit位置 */

    if ( dot )  /*  画实心点 */
        g_oled_gram[ x ][ pos ] |= temp;
    else
        g_oled_gram[ x ][ pos ] &= ~temp;
}

/* 16*16大小,字符A的点阵数据数组:*/
uint8_t oled_ascii_1608[]=
{
  0x00,0x04,0x00,0x3C,0x03,0xC4,0x1C,0x40,
  0x07,0x40,0x00,0xE4,0x00,0x1C,0x00,0x04
} ;

//字符显示代码
void oled_show_char_test(uint8_t  x, uint8_t  y, uint8_t mode)
{
    uint8_t temp, t1, t;
    uint8_t y0 = y;                 /* 保存y的初值 */

    for(t = 0; t < 16; t++)         /* 总共16个字节,要遍历一遍 */
    {
        temp = oled_ascii_1608[t];  /* 依次获取点阵数据 */

        for(t1 = 0; t1 < 8; t1++)
        {
            if(temp & 0X80)     /* 这个点有效,需要画出来 */
                oled_draw_point(x, y, mode);
            else                /* 这个点无效,不需要画出来 */
                oled_draw_point(x, y, !mode);

            temp <<= 1;         /* 低位数据往高位移位,最高位数据直接丢弃 */
            y++;                /* y坐标自增 */

            if((y - y0) == 16)  /* 显示完一列了 */
            {
                y = y0;         /* y坐标复位 */
                x++;            /* x坐标递增 */
                break;          /* 跳出 for循环 */
            }
        }
    }
}


/**
 * @brief       初始化OLED(SSD1306)
 * @param       无
 * @retval      无
 */
void oled_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();     /* 使能PORTC时钟 */
    __HAL_RCC_GPIOD_CLK_ENABLE();     /* 使能PORTD时钟 */
    __HAL_RCC_GPIOG_CLK_ENABLE();     /* 使能PORTG时钟 */
    
    /* PC0 ~ 7 设置 */
    gpio_init_struct.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_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;        /* 中速 */
    HAL_GPIO_Init(GPIOC, &gpio_init_struct);                /* PC0 ~ 7 设置 */

    gpio_init_struct.Pin = GPIO_PIN_3|GPIO_PIN_6;           /* PD3, PD6 设置 */
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;        /* 中速 */
    HAL_GPIO_Init(GPIOD, &gpio_init_struct);                /* PD3, PD6 设置 */
    
    gpio_init_struct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;        /* 中速 */
    HAL_GPIO_Init(GPIOG, &gpio_init_struct);                /* WR/RD/RST引脚模式设置 */

    OLED_WR(1);
    OLED_RD(1);

    OLED_CS(1);
    OLED_RS(1);
    
    /* 复位时序 */
    OLED_RST(0);
    delay_ms(100);
    OLED_RST(1);

    oled_wr_byte(0xAE, OLED_CMD);   /* 关闭显示 */
    oled_wr_byte(0xD5, OLED_CMD);   /* 设置时钟分频因子,震荡频率 */
    oled_wr_byte(80, OLED_CMD);     /* [3:0],分频因子;[7:4],震荡频率 */
    oled_wr_byte(0xA8, OLED_CMD);   /* 设置驱动路数 */
    oled_wr_byte(0X3F, OLED_CMD);   /* 默认0X3F(1/64) */
    oled_wr_byte(0xD3, OLED_CMD);   /* 设置显示偏移 */
    oled_wr_byte(0X00, OLED_CMD);   /* 默认为0 */

    oled_wr_byte(0x40, OLED_CMD);   /* 设置显示开始行 [5:0],行数. */

    oled_wr_byte(0x8D, OLED_CMD);   /* 电荷泵设置 */
    oled_wr_byte(0x14, OLED_CMD);   /* bit2,开启/关闭 */
    oled_wr_byte(0x20, OLED_CMD);   /* 设置内存地址模式 */
    oled_wr_byte(0x02, OLED_CMD);   /* [1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10; */
    oled_wr_byte(0xA1, OLED_CMD);   /* 段重定义设置,bit0:0,0->0;1,0->127; */
    oled_wr_byte(0xC8, OLED_CMD);   /* 设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数 */
    oled_wr_byte(0xDA, OLED_CMD);   /* 设置COM硬件引脚配置 */
    oled_wr_byte(0x12, OLED_CMD);   /* [5:4]配置 */

    oled_wr_byte(0x81, OLED_CMD);   /* 对比度设置 */
    oled_wr_byte(0xEF, OLED_CMD);   /* 1~255;默认0X7F (亮度设置,越大越亮) */
    oled_wr_byte(0xD9, OLED_CMD);   /* 设置预充电周期 */
    oled_wr_byte(0xf1, OLED_CMD);   /* [3:0],PHASE 1;[7:4],PHASE 2; */
    oled_wr_byte(0xDB, OLED_CMD);   /* 设置VCOMH 电压倍率 */
    oled_wr_byte(0x30, OLED_CMD);   /* [6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc; */

    oled_wr_byte(0xA4, OLED_CMD);   /* 全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏) */
    oled_wr_byte(0xA6, OLED_CMD);   /* 设置显示方式;bit0:1,反相显示;0,正常显示 */
    oled_wr_byte(0xAF, OLED_CMD);   /* 开启显示 */
    
}

//SSD1306(8080时序)写时序
void oled_data_out(uint8_t data)
{
    GPIOC->ODR = (GPIOC->ODR & 0XFF00) | (data & 0X00FF);
}


static void oled_wr_byte(uint8_t data, uint8_t cmd)
{
    OLED_RS (cmd);  /* 数据类型,由传参决定 */
    OLED_CS ( 0 );  /* 拉低片选线,选中SSD1306 */
    OLED_WR ( 0 );  /* 拉低WR线,准备数据 */
    oled_data_out(data); /* WR低电平期间,准备数据 */
    OLED_WR ( 1 );  /* 在WR上升沿,数据发出 */
    OLED_CS ( 1 );  /* 取消片选 */
    OLED_RS ( 1 );  /* 释放RS线,恢复默认 */
}

void oled_draw_point_test(uint8_t x, uint8_t y)
{
    /* 页地址模式 */
    uint8_t page_num = y / 8;
    
    /* 1、发送页地址 */
    oled_wr_byte(0xB0 | page_num, OLED_CMD);
    
    /* 2、发送列地址 */
    oled_wr_byte((x & 0x0F) | 0x00, OLED_CMD);      /* 列地址低四位 */
    oled_wr_byte((x & 0xF0) >> 4 | 0x10, OLED_CMD); /* 列地址高四位 */
    
    /* 3、发送1字节数据 */
    oled_wr_byte(1 << (y % 8), OLED_DATA);
}

void oled_clear(void)
{
    uint8_t i, n;

    for (i = 0; i < 8; i++)
    {
        oled_wr_byte (0xb0 + i, OLED_CMD); /* 设置页地址(0~7) */
        oled_wr_byte (0x00, OLED_CMD);     /* 设置显示位置—列低地址 */
        oled_wr_byte (0x10, OLED_CMD);     /* 设置显示位置—列高地址 */

        for (n = 0; n < 128; n++)
        {
            oled_wr_byte(0x00, OLED_DATA);
        }
    }
}

oled.h 

#ifndef __OLED_H
#define __OLED_H

#include "stdlib.h" 
#include "./SYSTEM/sys/sys.h"


/******************************************************************************************/
/* OLED 8080 模式引脚 定义 */

/* 片选脚 */
#define OLED_CS_PORT                GPIOD
#define OLED_CS_PIN                 GPIO_PIN_6
#define OLED_CS_CLK_ENABLE()        do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0)   /* PD口时钟使能 */

/* 数据类型脚 命令/数据*/
#define OLED_RS_PORT                GPIOD
#define OLED_RS_PIN                 GPIO_PIN_3
#define OLED_RS_CLK_ENABLE()        do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0)   /* PD口时钟使能 */

/* 向OLED读取数据脚 */
#define OLED_RD_PORT                GPIOG
#define OLED_RD_PIN                 GPIO_PIN_13
#define OLED_RD_CLK_ENABLE()        do{ __HAL_RCC_GPIOG_CLK_ENABLE(); }while(0)   /* PG口时钟使能 */

/* 向OLED写入数据脚 */
#define OLED_WR_PORT                GPIOG
#define OLED_WR_PIN                 GPIO_PIN_14
#define OLED_WR_CLK_ENABLE()        do{ __HAL_RCC_GPIOG_CLK_ENABLE(); }while(0)   /* PG口时钟使能 */

/* 复位脚 */
#define OLED_RST_PORT               GPIOG
#define OLED_RST_PIN                GPIO_PIN_15
#define OLED_RST_CLK_ENABLE()       do{ __HAL_RCC_GPIOG_CLK_ENABLE(); }while(0)   /* PG口时钟使能 */

/* 数据脚 */
#define OLED_DATA_PORT               GPIOC
#define OLED_DATA_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
#define OLED_DATA_CLK_ENABLE()       do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0)   /* PC口时钟使能 */
/******************************************************************************************/

/* OLED 8080模式相关端口控制函数 定义 */
#define OLED_RST(x)     do{ x ? \
                                  HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET) : \
                                  HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET); \
                        }while(0)       /* 设置RST引脚 */

#define OLED_CS(x)      do{ x ? \
                                  HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET) : \
                                  HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); \
                        }while(0)       /* 设置CS引脚 */
#define OLED_RS(x)      do{ x ? \
                                  HAL_GPIO_WritePin(OLED_RS_PORT, OLED_RS_PIN, GPIO_PIN_SET) : \
                                  HAL_GPIO_WritePin(OLED_RS_PORT, OLED_RS_PIN, GPIO_PIN_RESET); \
                        }while(0)       /* 设置RS引脚 */
                              
#define OLED_WR(x)      do{ x ? \
                                  HAL_GPIO_WritePin(OLED_WR_PORT, OLED_WR_PIN, GPIO_PIN_SET) :  \
                                  HAL_GPIO_WritePin(OLED_WR_PORT, OLED_WR_PIN, GPIO_PIN_RESET); \
                        } while (0)     /* 设置WR引脚 */

#define OLED_RD(x)      do{ x ? \
                                  HAL_GPIO_WritePin(OLED_RD_PORT, OLED_RD_PIN, GPIO_PIN_SET) : \
                                  HAL_GPIO_WritePin(OLED_RD_PORT, OLED_RD_PIN, GPIO_PIN_RESET); \
                        }while(0)       /* 设置RD引脚 */

/* 命令/数据 定义 */
#define OLED_CMD        0       /* 写命令 */
#define OLED_DATA       1       /* 写数据 */

/******************************************************************************************/
    
static void oled_wr_byte(uint8_t data, uint8_t cmd);    /* 写一个字节到OLED */
void oled_init(void);           /* OLED初始化 */


#endif



 

 main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/OLED/oled.h"

int main(void)
{
    HAL_Init();                             /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    delay_init(72);                         /* 延时初始化 */
    usart_init(115200);                     /* 串口初始化为115200 */
    led_init();                             /* 初始化LED */
    oled_init();
    oled_clear();
//一下四行是oled上画一个点
//    oled_draw_point_test(0, 0);
//    oled_draw_point_test(10, 0);
//    oled_draw_point_test(10, 10);
//    oled_draw_point_test(20, 20);
    
    oled_show_char_test(10, 10 ,1);
    oled_refresh_gram();
    
    while (1)
    {
        delay_ms(500);
        LED0_TOGGLE();                      /* LED0闪烁 */
    }

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
以下是使用STM32F103C8T6驱动OLED显示一段字符的示例代码。假设我们的OLED屏幕为128x64像素的SSD1306 OLED屏幕。 首先,需要在STM32CubeMX中配置相应的GPIO和SPI外设的引脚。假设我们使用PA5作为OLED屏幕的时钟引脚,PA7作为数据引脚。 1. 初始化SPI外设 ```c SPI_HandleTypeDef hspi1; void MX_SPI1_Init(void) { /* SPI1 parameter configuration*/ hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial = 10; if (HAL_SPI_Init(&hspi1) != HAL_OK) { Error_Handler(); } } ``` 2. 初始化OLED屏幕 ```c void OLED_Init(void) { OLED_Write_Cmd(0xAE); //关闭OLED OLED_Write_Cmd(0x20); //设置内存地址模式 OLED_Write_Cmd(0x10); //00,水平地址模式;01,垂直地址模式;10,页地址模式;默认为0x02 OLED_Write_Cmd(0xB0); //设置页地址 OLED_Write_Cmd(0xC8); //设置COM方向;bit3: 0,普通模式;1,反向模式 OLED_Write_Cmd(0x00); //设置低列地址 OLED_Write_Cmd(0x10); //设置高列地址 OLED_Write_Cmd(0x40); //设置显示开始行[0~63] OLED_Write_Cmd(0x81); //设置对比度 OLED_Write_Cmd(0xFF); //对比度调节 0x00~0xFF OLED_Write_Cmd(0xA1); //设置段重定向 OLED_Write_Cmd(0xA6); //设置正常/反向显示 OLED_Write_Cmd(0xA8); //设置多路复用率 OLED_Write_Cmd(0x3F); //默认0x3F(1/64) 0x1F(1/32) OLED_Write_Cmd(0xA4); //0xa4,输出按字节显示;0xa5,输出按bit显示 OLED_Write_Cmd(0xD3); //设置显示偏移 OLED_Write_Cmd(0x00); //不偏移 OLED_Write_Cmd(0xD5); //设置OSC分频比,低四位是分频比,高四位是时钟占空比 OLED_Write_Cmd(0xF0); //默认为0x80 OLED_Write_Cmd(0xD9); //设置预充电周期 OLED_Write_Cmd(0x22); //bit[1:0],Phase 1 (0x0~0xF) OLED_Write_Cmd(0xDA); //设置COM硬件引脚配置 OLED_Write_Cmd(0x12); OLED_Write_Cmd(0xDB); //设置VCOMH 电压倍率 OLED_Write_Cmd(0x20); //0x20,0.77xVcc OLED_Write_Cmd(0x8D); //设置DC-DC开关模式 OLED_Write_Cmd(0x14); //0x10,DC-DC ON;0x14,DC-DC OFF OLED_Write_Cmd(0xAF); //开启OLED } ``` 3. 写入指令和数据 ```c void OLED_Write_Cmd(uint8_t cmd) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); //拉低片选 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); //拉低CLK HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET); //拉低DAT HAL_SPI_Transmit(&hspi1, &cmd, 1, 1000); //发送数据 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); //拉高片选 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); //拉高CLK HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET); //拉高DAT } void OLED_Write_Data(uint8_t data) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); //拉低片选 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); //拉低CLK HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET); //拉高DAT HAL_SPI_Transmit(&hspi1, &data, 1, 1000); //发送数据 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); //拉高片选 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); //拉高CLK HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET); //拉高DAT } ``` 4. 在屏幕上显示字符 ```c void OLED_Show_Char(uint8_t x, uint8_t y, uint8_t chr) { uint8_t c = 0; uint8_t i = 0; c = chr - ' '; //得到偏移后的值 if (x > 120) { x = 0; y++; } OLED_Set_Pos(x, y); //设置显示位置 for (i = 0; i < 6; i++) OLED_Write_Data(F6x8[c][i]); } void OLED_Show_String(uint8_t x, uint8_t y, char *str) { uint8_t j = 0; uint8_t k = 0; while (str[k] != '\0') { OLED_Show_Char(x + j * 6, y, str[k]); j++; if (j > 20) break; k++; } } ``` 其中,F6x8是一个包含ASCII码字符的数组,用来表示字符的点阵信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从糕手变成高手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值