学习笔记:用STM32F103C8T6开发板在0.96寸oled屏幕上面显示数字、字母、汉字的代码解释

oled.c代码解释

#include "oled.h"
#include "i2c.h"
#include "oledfont.h"          // 包含OLED字体相关的头文件

// 初始化命令数组,用于初始化OLED屏幕
uint8_t CMD_Data[]={
0xAE, 0x00, 0x10, 0x40, 0xB0, 0x81, 0xFF, 0xA1, 0xA6, 0xA8, 0x3F,
                    
0xC8, 0xD3, 0x00, 0xD5, 0x80, 0xD8, 0x05, 0xD9, 0xF1, 0xDA, 0x12,
                    
0xD8, 0x30, 0x8D, 0x14, 0xAF};     

// 向OLED写入初始化命令的函数
void WriteCmd(void)
{
    uint8_t i = 0;
    // 循环遍历初始化命令数组
    for(i=0; i<27; i++)
    {
        // 通过I2C接口向OLED设备写入单个初始化命令
        HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,CMD_Data+i,1,0x100);
    }
}

// 向设备写控制命令的函数
void OLED_WR_CMD(uint8_t cmd)
{
    // 通过I2C接口向OLED设备写入单个控制命令
    HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,&cmd,1,0x100);
}

// 向设备写数据的函数
void OLED_WR_DATA(uint8_t data)
{
    // 通过I2C接口向OLED设备写入单个数据
    HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x40,I2C_MEMADD_SIZE_8BIT,&data,1,0x100);
}

// 初始化OLED屏幕的函数
void OLED_Init(void)
{ 	
    // 延时200ms,等待OLED设备稳定
    HAL_Delay(200);
 
    // 调用写入初始化命令的函数
    WriteCmd();
}

// 清屏函数
void OLED_Clear(void)
{
    uint8_t i,n;		    
    // 循环操作8页
    for(i=0;i<8;i++)  
    {  
        // 设置当前页地址
        OLED_WR_CMD(0xb0+i);
        // 设置列低地址
        OLED_WR_CMD (0x00); 
        // 设置列高地址
        OLED_WR_CMD (0x10); 
        // 循环清空每一列的数据
        for(n=0;n<128;n++)
            OLED_WR_DATA(0);
    } 
}

// 开启OLED显示的函数
void OLED_Display_On(void)
{
    // 发送设置DCDC命令
    OLED_WR_CMD(0X8D);  
    // 开启DCDC
    OLED_WR_CMD(0X14);  
    // 开启显示
    OLED_WR_CMD(0XAF);  
}

// 关闭OLED显示的函数
void OLED_Display_Off(void)
{
    // 发送设置DCDC命令
    OLED_WR_CMD(0X8D);  
    // 关闭DCDC
    OLED_WR_CMD(0X10);  
    // 关闭显示
    OLED_WR_CMD(0XAE);  
}

// 设置OLED显示位置的函数
void OLED_Set_Pos(uint8_t x, uint8_t y) 
{ 	
    // 设置页地址
    OLED_WR_CMD(0xb0+y);
    // 设置列高地址
    OLED_WR_CMD(((x&0xf0)>>4)|0x10);
    // 设置列低地址
    OLED_WR_CMD(x&0x0f);
} 

// 点亮OLED屏幕所有像素的函数
void OLED_On(void)  
{  
    uint8_t i,n;		    
    // 循环操作8页
    for(i=0;i<8;i++)  
    {  
        // 设置当前页地址
        OLED_WR_CMD(0xb0+i);    // 设置页地址(0~7)
        // 设置列低地址
        OLED_WR_CMD(0x00);      // 设置显示位置 - 列低地址
        // 设置列高地址
        OLED_WR_CMD(0x10);      // 设置显示位置 - 列高地址   
        // 循环点亮每一列的像素
        for(n=0;n<128;n++)
            OLED_WR_DATA(1); 
    } // 更新显示
}

// 计算m的n次方的函数
unsigned int oled_pow(uint8_t m,uint8_t n)
{
    unsigned int result=1;	 
    // 循环n次进行累乘
    while(n--)result*=m;    
    return result;
}

// 在OLED上显示数字的函数
// x,y :起始坐标
// len :数字的位数
// size:字体大小
// mode:模式 0,填充模式;1,叠加模式
// num:数值(0~4294967295);
void OLED_ShowNum(uint8_t x,uint8_t y,unsigned int num,uint8_t len,uint8_t size2)
{         	
    uint8_t t,temp;
    uint8_t enshow=0;						   
    // 循环处理每一位数字
    for(t=0;t<len;t++)
    {
        // 计算当前位的数字
        temp=(num/oled_pow(10,len-t-1))%10;
        if(enshow==0&&t<(len-1))
        {
            if(temp==0)
            {
                // 如果当前位为0且还未显示有效数字,则显示空格
                OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
                continue;
            }else enshow=1; 
        }
        // 显示当前位的数字
        OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2); 
    }
} 

// 在指定位置显示一个字符,包括部分字符
// x:0~127
// y:0~63
// mode:0,反白显示;1,正常显示
// size:选择字体 16/12 
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size)
{      	
    unsigned char c=0,i=0;	
    // 得到偏移后的值
    c=chr-' ';			
    if(x>128-1){x=0;y=y+2;}
    if(Char_Size ==16)
    {
        // 设置显示位置
        OLED_Set_Pos(x,y);	
        // 写入字符的上半部分数据
        for(i=0;i<8;i++)
            OLED_WR_DATA(F8X16[c*16+i]);
        // 设置显示位置到下一行
        OLED_Set_Pos(x,y+1);
        // 写入字符的下半部分数据
        for(i=0;i<8;i++)
            OLED_WR_DATA(F8X16[c*16+i+8]);
    }
    else {	
        // 设置显示位置
        OLED_Set_Pos(x,y);
        // 写入字符数据
        for(i=0;i<6;i++)
            OLED_WR_DATA(F6x8[c][i]);
    }
}

// 显示一个字符串的函数
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t Char_Size)
{
    unsigned char j=0;
    // 循环遍历字符串中的每个字符
    while (chr[j]!='\0')
    {
        // 显示当前字符
        OLED_ShowChar(x,y,chr[j],Char_Size);
        // 横坐标右移
        x+=8;
        if(x>120){x=0;y+=2;}
        j++;
    }
}

// 显示中文字符的函数
// hzk 用取模软件得出的数组
void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no)
{      			    
    uint8_t t,adder=0;
    // 设置显示位置
    OLED_Set_Pos(x,y);	
    // 写入中文字符的上半部分数据
    for(t=0;t<16;t++)
    {
        OLED_WR_DATA(Hzk[2*no][t]);
        adder+=1;
    }	
    // 设置显示位置到下一行
    OLED_Set_Pos(x,y+1);	
    // 写入中文字符的下半部分数据
    for(t=0;t<16;t++)
    {	
        OLED_WR_DATA(Hzk[2*no+1][t]);
        adder+=1;
    }					
}

main.c代码解释

#include "main.h"
#include "i2c.h"
#include "gpio.h"
#include "oled.h"

// 未使用的私有类型定义区域(目前为空)
// 可用于定义自定义的数据类型等
// 目前没有实际定义内容

// 未使用的私有宏定义区域(目前为空)
// 可用于定义一些宏,方便代码的修改和复用
// 目前没有实际定义内容

// 未使用的私有变量定义区域(目前为空)
// 可用于定义在main函数中使用的私有变量
// 目前没有实际定义内容

// 系统时钟配置函数声明
void SystemClock_Config(void);

// 主函数,程序的入口点
int main(void)
{
    // MCU初始化,包括重置所有外设、初始化Flash接口和Systick
    HAL_Init();

    // 配置系统时钟
    SystemClock_Config();

    // 初始化GPIO外设
    MX_GPIO_Init();
    // 初始化I2C1外设
    MX_I2C1_Init();

    // 初始化OLED屏幕
    OLED_Init();
    // 清空OLED屏幕
    OLED_Clear();
    // 在(0, 0)位置显示数字123456,数字位数为6,字体大小为16
    OLED_ShowNum(0,0,123456,6,16);
    // 在(0, 2)位置显示字符串"Hello World!",字体大小为16
    OLED_ShowString(0,2,"Hello World!",16);
    // 在(0, 4)位置显示第一个中文字符(根据索引0获取字符数据)
    OLED_ShowCHinese(0,4,0);
    // 在(16, 4)位置显示第二个中文字符(根据索引1获取字符数据)
    OLED_ShowCHinese(16,4,1);
    // 在(32, 4)位置显示第三个中文字符(根据索引2获取字符数据)
    OLED_ShowCHinese(32,4,2);

    // 无限循环,程序的主循环
    while (1)
    {
        // 目前循环内没有实际操作,可添加其他功能代码
    }
}

// 系统时钟配置函数
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    // 配置RCC振荡器,使用HSE(高速外部时钟)
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    // 使能HSE
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    // HSE预分频值为1
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    // 使能HSI(高速内部时钟)
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    // 使能PLL(锁相环)
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    // PLL的时钟源为HSE
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    // PLL的倍频系数为9
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    // 配置RCC振荡器,如果配置失败则调用错误处理函数
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    // 配置CPU、AHB和APB总线时钟
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                  |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    // 系统时钟源为PLL时钟
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    // AHB时钟分频系数为1
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    // APB1时钟分频系数为2
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    // APB2时钟分频系数为1
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    // 配置时钟,如果配置失败则调用错误处理函数
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    {
        Error_Handler();
    }
}

// 错误处理函数,在发生错误时被调用
void Error_Handler(void)
{
    // 禁用中断
    __disable_irq();
    // 进入无限循环,使程序停在这里
    while (1)
    {
    }
}

// 断言失败处理函数(用于调试,目前为空实现)
// 当assert_param函数检查到错误参数时调用
// 可用于报告错误发生的源文件名和行号
void assert_failed(uint8_t *file, uint32_t line)
{
    // 可添加代码用于报告文件名和行号
    // 目前没有实际实现
}

oled.h代码解释

#ifndef __OLED_H__
// 防止头文件被重复包含的宏定义
#define __OLED_H__

#include "stm32f1xx_hal.h"
// 包含STM32F1系列的HAL库头文件,提供硬件抽象层的功能

//ʹÓÃÓ²¼þI2C1
///
#define   OLED_GPIO_CLK_ENABLE()         __HAL_RCC_GPIOA_CLK_ENABLE()
// 定义宏,用于使能GPIOA的时钟。这里可能存在一个小错误,
// 因为后续使用的是GPIOB相关引脚,而这里使能的是GPIOA的时钟,
// 或许应该是使能GPIOB的时钟(__HAL_RCC_GPIOB_CLK_ENABLE())

#define   GPIOx_OLED_PORT               GPIOB
// 定义宏,表示OLED相关引脚所在的GPIO端口为GPIOB

#define   OLED_SCK_PIN                  GPIO_PIN_8
// 定义宏,表示OLED的时钟信号(SCK)所连接的引脚为GPIOB的第8号引脚

#define   OLED_SCK_ON()                 HAL_GPIO_WritePin(GPIOx_OLED_PORT, OLED_SCK_PIN, GPIO_PIN_SET)
// 定义宏,将OLED的SCK引脚设置为高电平

#define   OLED_SCK_OFF()                HAL_GPIO_WritePin(GPIOx_OLED_PORT, OLED_SCK_PIN, GPIO_PIN_RESET)
// 定义宏,将OLED的SCK引脚设置为低电平

#define   OLED_SCK_TOGGLE()             HAL_GPIO_TogglePin(GPIOx_OLED_PORT, OLED_SCK_PIN)
// 定义宏,翻转OLED的SCK引脚电平

#define   OLED_SDA_PIN                  GPIO_PIN_9
// 定义宏,表示OLED的数据信号(SDA)所连接的引脚为GPIOB的第9号引脚

#define   OLED_SDA_ON()                 HAL_GPIO_WritePin(GPIOx_OLED_PORT, OLED_SDA_PIN, GPIO_PIN_SET)
// 定义宏,将OLED的SDA引脚设置为高电平

#define   OLED_SDA_OFF()                HAL_GPIO_WritePin(GPIOx_OLED_PORT, OLED_SDA_PIN, GPIO_PIN_RESET)
// 定义宏,将OLED的SDA引脚设置为低电平

#define   OLED_SDA_TOGGLE()             HAL_GPIO_TogglePin(GPIOx_OLED_PORT, OLED_SDA_PIN)
// 定义宏,翻转OLED的SDA引脚电平
///

// 函数声明:向OLED写入初始化命令的函数
void WriteCmd(void);
// 函数声明:向OLED设备写控制命令的函数
void OLED_WR_CMD(uint8_t cmd);
// 函数声明:向OLED设备写数据的函数
void OLED_WR_DATA(uint8_t data);
// 函数声明:初始化OLED屏幕的函数
void OLED_Init(void);
// 函数声明:清屏函数
void OLED_Clear(void);
// 函数声明:开启OLED显示的函数
void OLED_Display_On(void);
// 函数声明:关闭OLED显示的函数
void OLED_Display_Off(void);
// 函数声明:设置OLED显示位置的函数
void OLED_Set_Pos(uint8_t x, uint8_t y);
// 函数声明:点亮OLED屏幕所有像素的函数
void OLED_On(void);
// 函数声明:在OLED上显示数字的函数
void OLED_ShowNum(uint8_t x,uint8_t y,unsigned int num,uint8_t len,uint8_t size2);
// 函数声明:在指定位置显示一个字符的函数
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size);
// 函数声明:显示一个字符串的函数
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t Char_Size);
// 函数声明:显示中文字符的函数
void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no);


#endif

 

oledfont.h代码解释

#ifndef __OLEDFONT_H__
#define __OLEDFONT_H__
 
#include "stm32f1xx_hal.h"


// 部分汉字点阵数据,每个汉字由32个字节表示,用于在OLED等设备上显示汉字
// 每个汉字的点阵数据分为上下两部分,各16个字节,组合起来形成16x16的点阵
const unsigned char Hzk[][32]=
{
    // 汉字“角”的点阵数据
    {
        // 上半部分点阵数据,每一个字节的8位对应点阵的一行中的8个点
        0x20,0x10,0xE8,0x24,0x27,0x24,0x24,0xE4,0x24,0x34,0x2C,0x20,0xE0,0x00,0x00,0x00,
        // 下半部分点阵数据
        0x80,0x60,0x1F,0x09,0x09,0x09,0x09,0x7F,0x09,0x09,0x49,0x89,0x7F,0x00,0x00,0x00
    }, /*"角",0*/
    /* (16 X 16 , 宋体 )*/

    // 汉字“度”的点阵数据
    {
        0x00,0x00,0xFC,0x24,0x24,0x24,0xFC,0x25,0x26,0x24,0xFC,0x24,0x24,0x24,0x04,0x00,
        0x40,0x30,0x8F,0x80,0x84,0x4C,0x55,0x25,0x25,0x25,0x55,0x4C,0x80,0x80,0x80,0x00
    }, /*"度",1*/
    /* (16 X 16 , 宋体 )*/

    // 汉字“值”的点阵数据
    {
        0x00,0x80,0x60,0xF8,0x07,0x04,0xE4,0xA4,0xA4,0xBF,0xA4,0xA4,0xE4,0x04,0x00,0x00,
        0x01,0x00,0x00,0xFF,0x40,0x40,0x7F,0x4A,0x4A,0x4A,0x4A,0x4A,0x7F,0x40,0x40,0x00
    }, /*"值",2*/
    /* (16 X 16 , 宋体 )*/

    // 汉字“电”的点阵数据
    {
        0x00,0x00,0xF8,0x88,0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x88,0xF8,0x00,0x00,0x00,
        0x00,0x00,0x1F,0x08,0x08,0x08,0x08,0x7F,0x88,0x88,0x88,0x88,0x9F,0x80,0xF0,0x00
    }, /*"电",3*/
    /* (16 X 16 , 宋体 )*/

    // 汉字“压”的点阵数据
    {
        0x00,0x00,0xFE,0x02,0x82,0x82,0x82,0x82,0xFA,0x82,0x82,0x82,0x82,0x82,0x02,0x00,
        0x80,0x60,0x1F,0x40,0x40,0x40,0x40,0x40,0x7F,0x40,0x40,0x44,0x58,0x40,0x40,0x00
    }, /*"压",4*/
    /* (16 X 16 , 宋体 )*/

    // 汉字“值”的点阵数据(这里重复定义了“值”,可能是为了方便调用)
    {
        0x00,0x80,0x60,0xF8,0x07,0x04,0xE4,0xA4,0xA4,0xBF,0xA4,0xA4,0xE4,0x04,0x00,0x00,
        0x01,0x00,0x00,0xFF,0x40,0x40,0x7F,0x4A,0x4A,0x4A,0x4A,0x4A,0x7F,0x40,0x40,0x00
    }, /*"值",5*/
    /* (16 X 16 , 宋体 )*/

    // 字符“:”的点阵数据
    {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    }, /*":",6*/
    /* (16 X 16 , 宋体 )*/
};


#endif

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

DIY机器人工房

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

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

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

打赏作者

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

抵扣说明:

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

余额充值