从0开始点亮OLED屏幕(四)OLED显示数字,十六进制数字

在上篇介绍了如何让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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值