在上篇介绍了如何让OLED显示字符以及字符串,下面来讲解一下如何显示数字等。直接进入正题:
1.OLED显示数字:
显示数字原理是什么呢?其实也是调用上次介绍的显示字符的函数了,但是如何提取出数字是个问题,在这里先介绍一个函数
//m^n
u32 OLED_Pow(u8 m,u8 n)
{
u32 result=1;
while(n--)
{
result*=m;
}
return result;
}
这个函数就是算出m^n次幂,当m=10,n为数字长度就可以依次取出数字了,比如12345/OLED_Pow(10,len-t-1))%10;每算一次就可以依次提出高位。
下面来介绍数字显示函数:除了8号的字符,其余的字符宽度等于其字号除2,8号大小的字符宽度为6,故除2后还得加上2。(size1/2+m)*t为每显示一个数字后的增量,初始坐标加上这个增量就是即将要显示数字的坐标了。temp即为将哟啊显示的数字,为0到9,而我们是以字符的形式显示的,故因该加上字符0来显示。
//显示数字
//x,y :起点坐标
//num :要显示的数字
//len :数字的位数
//size:字体大小
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1)
{
u8 t,temp,m=0;
if(size1==8) m=2;
for(t=0;t<len;t++)
{
temp=(num/OLED_Pow(10,len-t-1))%10;
if(temp==0)
OLED_ShowChar(x+(size1/2+m)*t,y,'0',size1);
else
OLED_ShowChar(x+(size1/2+m)*t,y,temp+'0',size1);
}
}
但是我认为这个函数不太方便,每次都要自己输入数字位数,且比如显示123而你输入显示4位数字时就是0123,对于强迫症的我很不友好,下面来对这个函数进行改进:只需要这样修改代码就好啦。还是很简单的,每次除10判断数字长度。
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 size1)
{
u8 t,temp,m=0,len;
u32 num1 = num;
if(size1==8) m=2;
while(num1)
{ len++; num1 /= 10; }
for(t=0;t<len;t++)
{
temp=(num/OLED_Pow(10,len-t-1))%10;
if(temp==0)
OLED_ShowChar(x+(size1/2+m)*t,y,'0',size1);
else
OLED_ShowChar(x+(size1/2+m)*t,y,temp+'0',size1);
}
}
2.OLED显示16进制数:
那么如何显示16位进制的数呢?
void OLED_ShowHexNum(u8 x,u8 y,u32 num,u8 size1)
{
u8 t,temp,len=0;
u32 num1 = num;
while(num1)
{ len++; num1 /= 16; }
OLED_ShowString(x,y,"0X",size1);
for(t=0;t<len;t++)
{
temp=(num/OLED_Pow(16,len-t-1))%16;
if(temp<10)
OLED_ShowNum(x+(size1/2)*(t+2),y,temp,size1);
else
OLED_ShowChar(x+(size1/2)*(t+2),y,temp+55,size1);
}
}
其原理和上面类似,就不再介绍了。
下面附上源码
oled.c
#include "oled.h"
#include "oledfont.h"
u8 OLED_GRAM[128][8];
//延时
void IIC_delay(void)
{
u8 t=3; while(t--);
}
//起始信号
void I2C_Start(void)
{
SDA_OUT();//将SDA口配置成输出
OLED_SDA(1);
OLED_SCL(1);
IIC_delay();
OLED_SDA(0);
IIC_delay();
OLED_SCL(0);
IIC_delay();
}
//结束信号,SCL高电平情况下,SDA信号由低变高
void I2C_Stop(void)
{
SDA_OUT();//将SDA口配置成输出
OLED_SDA(0);
OLED_SCL(1);
IIC_delay();
OLED_SDA(1);
}
//等待信号响应
void I2C_WaitAck(void) //测数据信号的电平
{
SDA_IN();//SDA设置为输入
IIC_delay();
OLED_SCL(1);
IIC_delay();
OLED_SCL(0);
IIC_delay();
}
//写入一个字节
void Send_Byte(u8 dat)
{
u8 i;
SDA_OUT();//将SDA口配置成输出
OLED_SCL(0);
for(i=0;i<8;i++)
{
OLED_SDA((BitAction)(dat&(0x80>>i)));
IIC_delay();
OLED_SCL(1);
IIC_delay();
OLED_SCL(0);
}
}
uint8_t Receive_Byte(void)
{
unsigned char i,dat=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
OLED_SCL(0);
IIC_delay();
OLED_SCL(1);
dat<<=1;
if(READ_SDA)
dat |= 1;
IIC_delay();
}
return dat;
}
//发送一个字节
//mode:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 mode)
{
I2C_Start();
Send_Byte(0x78);
I2C_WaitAck();
if(mode)
Send_Byte(0x40);
else
Send_Byte(0x00);
I2C_WaitAck();
Send_Byte(dat);
I2C_WaitAck();
I2C_Stop();
}
//更新显存到OLED
void OLED_Refresh(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
OLED_WR_Byte(0x00,OLED_CMD); //设置低列起始地址
OLED_WR_Byte(0x10,OLED_CMD); //设置高列起始地址
for(n=0;n<128;n++)
{
OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);
}
I2C_Stop();
}
}
//清屏函数
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
for(n=0;n<128;n++)
{
OLED_GRAM[n][i]=0;//清除所有数据
}
}
OLED_Refresh();//更新显示
}
//画点 x:0~127 y:0~63
void OLED_DrawPoint(u8 x,u8 y)
{
u8 i,m,n;
i=y/8;//算出为第几页
m=y%8;//算出点亮第几个像素点
n=1<<m;//将此像素点转换为8位的数据
OLED_GRAM[x][i]|=n;//将此像素点加上原来的数据
}
//清除一个点 x:0~127 y:0~63
void OLED_ClearPoint(u8 x,u8 y)
{
u8 i,m,n;
i=y/8;//算出为第几页
m=y%8;//算出点亮第几个像素点
n=1<<m;//将此像素点转换为8位的数据
OLED_GRAM[x][i]&=~n;
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//size1:选择字体 6x8/6x12/8x16/12x24
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1)
{
u8 i,m,temp,size2,chr1;
u8 x0=x,y0=y;
if(size1==8)size2=6;
else size2=(size1/8+((size1%8)?1:0))*(size1/2); //得到字体一个字符对应点阵集所占的字节数
chr1=chr-' '; //计算偏移后的值
for(i=0;i<size2;i++)
{
if(size1==8)
{temp=asc2_0806[chr1][i];} //调用0806字体
else if(size1==12)
{temp=asc2_1206[chr1][i];} //调用1206字体
else if(size1==16)
{temp=asc2_1608[chr1][i];} //调用1608字体
else if(size1==24)
{temp=asc2_2412[chr1][i];} //调用2412字体
else return;
for(m=0;m<8;m++)
{
if(temp&0x01)
OLED_DrawPoint(x,y);
temp>>=1;
y++;
}
x++;
if((size1!=8)&&((x-x0)==size1/2))
{x=x0;y0=y0+8;}
y=y0;
}
}
//显示字符串
//x,y:起点坐标
//size1:字体大小
//*chr:字符串起始地址
//mode:0,反色显示;1,正常显示
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1)
{
while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!
{
OLED_ShowChar(x,y,*chr,size1);
if(size1==8)x+=6;
else x+=size1/2;
chr++;
}
}
//m^n
u32 OLED_Pow(u8 m,u8 n)
{
u32 result=1;
while(n--)
{
result*=m;
}
return result;
}
//显示数字
//x,y :起点坐标
//num :要显示的数字
//len :数字的位数
//size:字体大小
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 size1)
{
u8 t,temp,m=0,len=0;
u32 num1 = num;
if(size1==8) m=2;
while(num1)
{ len++; num1 /= 10; }
for(t=0;t<len;t++)
{
temp=(num/OLED_Pow(10,len-t-1))%10;
if(temp==0)
OLED_ShowChar(x+(size1/2+m)*t,y,'0',size1);
else
OLED_ShowChar(x+(size1/2+m)*t,y,temp+'0',size1);
}
}
void OLED_ShowHexNum(u8 x,u8 y,u32 num,u8 size1)
{
u8 t,temp,len=0;
u32 num1 = num;
while(num1)
{ len++; num1 /= 16; }
OLED_ShowString(x,y,"0X",size1);
for(t=0;t<len;t++)
{
temp=(num/OLED_Pow(16,len-t-1))%16;
if(temp<10)
OLED_ShowNum(x+(size1/2)*(t+2),y,temp,size1);
else
OLED_ShowChar(x+(size1/2)*(t+2),y,temp+55,size1);
}
}
//OLED的初始化
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能A端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA0,1
GPIO_SetBits(GPIOA,GPIO_Pin_11|GPIO_Pin_12);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA2
GPIO_SetBits(GPIOA,GPIO_Pin_15);
OLED_WR_Byte(0xAE,OLED_CMD);//关闭显示(进入睡眠模式)
OLED_WR_Byte(0x02,OLED_CMD);//设置低列地址
OLED_WR_Byte(0x10,OLED_CMD);//设置高列地址
OLED_WR_Byte(0xD5,OLED_CMD);//设置显示时钟分频值/震荡频率(刷新率)
OLED_WR_Byte(0x80,OLED_CMD);//设置分割比率,设置时钟为100帧/秒
OLED_WR_Byte(0xA8,OLED_CMD);//设置复用率(0-63)
OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
OLED_WR_Byte(0xD3,OLED_CMD);//设置显示偏移一位映射RAM计数器(0x00~0x3F)
OLED_WR_Byte(0x00,OLED_CMD);//不偏移
OLED_WR_Byte(0x40,OLED_CMD);//设置起始地址 设置映射RAM显示起始行(0x00~0x3F)
OLED_WR_Byte(0xA1,OLED_CMD);//设置左右方向显示 0xa1正常 0xa0左右反置
OLED_WR_Byte(0xC8,OLED_CMD);//设置上下方向显示 0xc0上下反置 0xc8正常
OLED_WR_Byte(0xDA,OLED_CMD);//设置列引脚硬件配置
OLED_WR_Byte(0x12,OLED_CMD);//12864->0x12;128*32->0x02;
OLED_WR_Byte(0x81,OLED_CMD);//设置对比度控制寄存器
OLED_WR_Byte(0xCF,OLED_CMD);//设置对比度控制为0xcf(0x00-0xff)
OLED_WR_Byte(0xD9,OLED_CMD);//设置充电周期
OLED_WR_Byte(0xF1,OLED_CMD);//设置预充电为15个时钟,放电为1个时钟
OLED_WR_Byte(0xDB,OLED_CMD);//设置VCOMH反压值
OLED_WR_Byte(0x30,OLED_CMD);//设置VCOM取消选择电平
OLED_WR_Byte(0x20,OLED_CMD);//设置页面寻址模式(0x00/0x01/0x02)
OLED_WR_Byte(0xA6,OLED_CMD);//设置正常显示
OLED_Clear();
OLED_WR_Byte(0x8D,OLED_CMD);//设置电荷泵
OLED_WR_Byte(0x14,OLED_CMD);//设置电荷泵开启/(0x10)禁用
OLED_WR_Byte(0xAF,OLED_CMD);//开启显示(进入工作模式)
}
oled.h
#ifndef __OLED_H
#define __OLED_H
#include "sys.h"
#include "stdlib.h"
//-----------------OLED端口定义----------------
#define GPIO_SCL_PORT GPIOA
#define GPIO_SCL_PIN GPIO_Pin_11
#define GPIO_SCL_ENABLE() do{ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); }while(0) /* 所在IO口时钟使能 */
#define GPIO_SDA_PORT GPIOA
#define GPIO_SDA_PIN GPIO_Pin_12
#define GPIO_SDA_ENABLE() do{ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); }while(0) /* 所在IO口时钟使能 */
#define OLED_SCL(x) GPIO_SCL_PORT->BSRR = GPIO_SCL_PIN << (16*(!x))
#define OLED_SDA(x) GPIO_SDA_PORT->BSRR = GPIO_SDA_PIN << (16*(!x))
#define SDA_IN() {GPIOA->CRH &= 0XFFF0FFFF;GPIOA->CRH |= (u32)8<<16;}
#define SDA_OUT() {GPIOA->CRH &= 0XFFF0FFFF;GPIOA->CRH |= (u32)3<<16;}
#define READ_SDA (BitAction)(GPIOA->IDR & GPIO_Pin_12)
#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据
void I2C_Start(void);
void I2C_Stop(void);
void I2C_WaitAck(void);
void Send_Byte(u8 dat);
void OLED_WR_Byte(u8 dat,u8 mode);
void OLED_Refresh(void);
void OLED_Clear(void);
void OLED_DrawPoint(u8 x,u8 y);
void OLED_ClearPoint(u8 x,u8 y);
void OLED_Init(void);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1);
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 size1);
void OLED_ShowHexNum(u8 x,u8 y,u32 num,u8 size1);
#endif
#include "oledfont.h"
#ifndef __OLEDFONT_H
#define __OLEDFONT_H
const unsigned char asc2_0806[][6] =
{
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},// sp
{0x00, 0x00, 0x00, 0x2f, 0x0

3003

被折叠的 条评论
为什么被折叠?



