在跟着我未曾谋面的恩师——江协科技学习STM32时,学到OLED这一块的时候使用的是标准库下的软件I2C。但我现在工作基本都是使用HAL库,而且硬件I2C相比与软件I2C更好配置,由此我产生了将程序移植过来的想法。
直接上打包好的连接,使用的是STM32F103C8T6的I2C1:
链接:https://pan.baidu.com/s/1SbDAPaLdGz9rS9gPA4Dkzg?pwd=1vqx
提取码:1vqx
一,修改的部分
说是移植,其实就是命令的收发由软件控制改为硬件控制。
发送命令
void OLED_SendCmd(uint8_t cmd)
{
uint8_t sendbuf[2];
sendbuf[0]=0x00;//写命令
sendbuf[1]=cmd;
HAL_I2C_Master_Transmit(&hi2c1,OLED_ADDRESS,sendbuf,2,100);
}
发送一位数据
void OLED_SendData(uint8_t data)
{
uint8_t sendbuf[2];
sendbuf[0]=0x40;//写数据
sendbuf[1]=data;
HAL_I2C_Master_Transmit(&hi2c1,OLED_ADDRESS,sendbuf,2,100);
}
发送定长数据
void OLED_SendDataByLength(uint8_t* data,uint8_t len)
{
uint8_t sendbuf[128]={0};
sendbuf[0]=0x40;
for(uint8_t i=0;i<len;i++)
{
sendbuf[i+1]=data[i];
}
HAL_I2C_Master_Transmit(&hi2c1,OLED_ADDRESS,sendbuf,len+1,100);
}
设置光标
void OLED_SetCursor(uint8_t y,uint8_t x)
{
OLED_SendCmd(0xB0|y);
OLED_SendCmd(0x10|(x&0xF0)>>4);
OLED_SendCmd(0x00|(x&0x0F));
}
其他的地方还做了一些小修改,比如除了显示十六进制数以外,显示其他类型的数据不需要传入长度
//显示字符串
void OLED_ShowString(uint8_t line,uint8_t column,char* str)
{
for(uint8_t i=0;str[i]!='\0';i++)
{
OLED_ShowChar(line,column+i,str[i]);
}
}
//显示十进制无符号数
void OLED_ShowNum(uint8_t line,uint8_t column,uint32_t num)
{
uint8_t length=0;
uint32_t tmp=num;
while(tmp)
{
length++;//根据传入的数字计算显示的长度
tmp/=10;
}
for(uint8_t i=0;i<length;i++)
{
OLED_ShowChar(line,column+i,num/OLED_Pow(10,length-i-1)%10+'0');
}
}
//显示十进制有符号数
void OLED_ShowSignedNum(uint8_t line,uint8_t column,int32_t num)
{
uint8_t length=0;
int32_t tmp=num;
uint32_t number;
while(tmp)
{
length++;
tmp/=10;
}
if(num>=0)
{
OLED_ShowChar(line,column,'+');
number=num;
}
else
{
OLED_ShowChar(line,column,'-');
number=-num;
}
for(uint8_t i=0;i<length;i++)
{
OLED_ShowChar(line,column+i+1,number/OLED_Pow(10,length-i-1)%10+'0');
}
}
//显示二进制数
void OLED_ShowBinNum(uint8_t line,uint8_t column,int32_t num)
{
uint8_t length=0;
int32_t tmp=num;
while(tmp)
{
length++;
tmp>>=1;
}
for(uint8_t i=0;i<length;i++)
{
OLED_ShowChar(line,column+i,num/OLED_Pow(2,length-i-1)%2+'0');
}
}
显示十六进制数的时候仍要添加长度参数
void OLED_ShowHexNum(uint8_t line,uint8_t column,int32_t num,uint8_t len)
{
uint8_t single;
OLED_ShowString(line,column,"0x");
for(uint8_t i=0;i<len;i++)
{
single=num/OLED_Pow(16,len-i-1)%16;
if(single<10)
{
OLED_ShowChar(line,column+i+2,single+'0');
}
else{
OLED_ShowChar(line,column+i+2,single+'A'-10);
}
}
}
二,新加功能
对于up主江协科技与12月1日发布的OLED模块教学视频添加的新函数进行了移植,大部分都是直接粘的,新功能改为更加科学的修改显存数组的方式修改图片内容,调用更新函数进行显示的方法。
大部分的函数无脑cv即可,这里只说明一下有修改的函数
/*
* X:起始点的x坐标
* Y:起始点的y坐标
* Char:要显示的字符
* FontSize:显示的尺寸
*/
void OLED_ShowCharByImage(uint8_t X, uint8_t Y, char Char, uint8_t FontSize)
{
if (FontSize == OLED_8X16) //字体为宽8像素,高16像素
{
/*将ASCII字模库OLED_F8x16的指定数据以8*16的图像格式显示*/
OLED_ShowImage(X, Y, 8, 16, OLED_F8x16[Char - ' ']);
}
else if(FontSize == OLED_6X8) //字体为宽6像素,高8像素
{
/*将ASCII字模库OLED_F6x8的指定数据以6*8的图像格式显示*/
OLED_ShowImage(X, Y, 6, 8, OLED_F6x8[Char - ' ']);
}
}
/*
* X:起始点的x坐标
* Y:起始点的y坐标
* String:要显示的字符串
* FontSize:显示的尺寸
*/
void OLED_ShowStringByLength(uint8_t X, uint8_t Y, char *String, uint8_t FontSize)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i++) //遍历字符串的每个字符
{
/*调用OLED_ShowChar函数,依次显示每个字符*/
OLED_ShowCharByImage(X + i * FontSize, Y, String[i], FontSize);
}
}
这两个函数在江协科技的工程中叫做OLED_ShowChar()和OLED_ShowString(),由于与最开始的函数名冲突,因而对函数名进行了修改,具体功能不变
三,关于OLED_Clear()方法
- OLED_Clear() 清空显存数组,需要配合OLED_Update()
- OLED_ClearArea() 清空部分显存数组,需要配合OLED_Update()
- OLED_ClearImmediately() 直接向OLED发送数据,将所有像素点写入0x00
四,OLED_ShowChinese()中遇到的问题
在OLED_Data.h文件中添加了编码格式的适配,我这里采用的是GB2312的编码格式,而江协科技采用的UTF-8。想要正常使用,必须用编码格式转换软件将这几个OLED文件转成你用的格式然后再添加进工程,直接使用keil中的小扳手更改编码格式再重编译是没有的,没错,我就这么犯傻了
五,涉及到的函数
stm32系列OLED相关中的函数是直接向OLED发送命令,不需要更新,后续更新OLED功能是通过对显存数组进行操作,需要通过OLED_Update()进行显示才会生效
六,函数注释
大部分我写的函数都没有添加注释,具体使用方法请认准本家 B站up主:江协科技。jiangxiekeji.com