STM32 OLED 0.96 SPI总线 中文显示 和 TFTLCD共享字库

前言

中文字库已经有了不过是TFTLCD驱动里的, 专门再给OLED写字库有些浪费内存, 所以要复用下. 开发板SPI2总线空着正好用

硬件连接和字段定义, OLED是只写硬件MISO线用不到, 注意电压匹配和正负极尽量被插错

#define OLED_CS   	PGout(7)//CS   片选		            
#define OLED_DC   	PGout(8)  //DC   命令数据控制	
#define OLED_RST  	PGout(6)  //RES  复位  
#define OLED_DATA  	PBout(15) //D1   数据   SPI2_MOSI	
#define OLED_CLK  	PBout(13) //D0   时钟   SPI2_SCK

在这里插入图片描述

GPIO 引脚初始化

GPIO_InitTypeDef  GPIO_InitStructure;
SPI_InitTypeDef  SPI_InitStructure;
/* GPIOB打开时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOG, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_7|GPIO_Pin_6; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 	//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //速度50MHz
GPIO_Init(GPIOG, &GPIO_InitStructure);	 
GPIO_SetBits(GPIOG,GPIO_Pin_8|GPIO_Pin_7|GPIO_Pin_6);	//拉高电平

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 	//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);	 
GPIO_SetBits(GPIOB, GPIO_Pin_12);	    //拉高电平 GPIO_Pin_12 是 flash片选

/* SPI2外设打开时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

/* SPI2的IO口设置 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PB13/14/15复用推挽输出 
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);

/* SPI2的模式设置 */
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;  //设置SPI2单向或者双向的数据模式:SPI2设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//设置SPI2工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;	//设置SPI2的数据大小:SPI2发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//串行同步时钟的空闲状态为高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;		//定义波特率预分频的值:波特率预分频值为256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure);         //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
SPI_CalculateCRC(SPI2, DISABLE);            //关闭crc
SPI_Cmd(SPI2, ENABLE); //使能SPI外设

OLED 硬件初始化, 这段比较繁琐还好由供应商提供

   /*  重置硬件 */
  OLED_RST=1; 
  delay_ms(100);
  OLED_RST=0;
  delay_ms(100);
  OLED_RST=1; 
	
  select();  // 片选
	
  OLED_WR_Cmd(0xAE);//关闭显示
     
  OLED_WR_Cmd(0x00);//X轴低位,起始X轴为0
  OLED_WR_Cmd(0x10);//X轴高位
  OLED_WR_Cmd(0x40);//Y轴,可设区间[0x40,0x7F],设置为0了
     
  OLED_WR_Cmd(0xA1);//设置X轴扫描方向,0xa0左右反置 ,0xa1正常(左边为0列)
  OLED_WR_Cmd(0xC8);//设置Y轴扫描方向,0xc0上下反置 ,0xc8正常(上边为0行)
  OLED_WR_Cmd(0xA6);//位值表示的意义,0xa6表示正常,1为点亮,0为关闭,0xa7显示效果相反
     
  OLED_WR_Cmd(0x81);//命令头,调节亮度,对比度,变化很小,但是仔细可以观察出来
  OLED_WR_Cmd(0xFF);//可设置区间[0x00,0xFF]
     
  OLED_WR_Cmd(0xA8);//命令头,设置多路复用率(1 to 64)
  OLED_WR_Cmd(0x3f);//--1/64 duty
     
  OLED_WR_Cmd(0xD3);//命令头,设置显示偏移移位映射RAM计数器(0x00~0x3F)
  OLED_WR_Cmd(0x00);//不偏移
     
  OLED_WR_Cmd(0xd5);//命令头,设置显示时钟分频比/振荡器频率
  OLED_WR_Cmd(0x80);//设置分割比率,设置时钟为100帧/秒
     
  OLED_WR_Cmd(0xD9);//命令头,--set pre-charge period
  OLED_WR_Cmd(0xF1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
     
  OLED_WR_Cmd(0xDA);//命令头,--set com pins hardware configuration
  OLED_WR_Cmd(0x12);
     
  OLED_WR_Cmd(0xDB);//命令头,--set vcomh
  OLED_WR_Cmd(0x40);//Set VCOM Deselect Level
     
  OLED_WR_Cmd(0x20);//命令头,设置寻址模式
  OLED_WR_Cmd(0x10);//页面寻址模式(重置) (0x00/0x01/0x02)
     
  OLED_WR_Cmd(0x8D);//命令头,--set Charge Pump enable/disable
  OLED_WR_Cmd(0x14);//--set(0x10) disable
     
  OLED_WR_Cmd(0xA4);//恢复到RAM内容显示(重置)    						   
  OLED_WR_Cmd(0xAF);//开启显示	  
	
  OLED_Clearby_Gram(0x00);   
	
 unselect();  //反片选

OLED 核心写入逻辑

 /* SPI2 硬件写入 */
 void SPI2_WriteOLEDByte(u8 TxData)
{		
	while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); // 等待可发送
	SPI_I2S_SendData(SPI2, TxData); //通过外设SPI2发送一个byte数据
}

/* 写命令 */
void OLED_WR_Cmd(u8 data)
{				  
	OLED_DC=OLED_CMD_F;  			            //命令状态  
	select();
	SPI2_WriteOLEDByte(data);               	//写入一个字节  
	unselect();
} 

/* 写数据 */
void OLED_WR_Data(u8 data)
{	
	OLED_DC=OLED_DATA_F;                        //数据状态
	select();
	SPI2_WriteOLEDByte(data);               	//写入一个字节 
	unselect();	
} 

画汉字核心逻辑

//OLED的显存
//[0]0 1 2 3 ... 127	
//[1]0 1 2 3 ... 127	
//[2]0 1 2 3 ... 127	
//[3]0 1 2 3 ... 127	
//[4]0 1 2 3 ... 127	
//[5]0 1 2 3 ... 127	
//[6]0 1 2 3 ... 127	
//[7]0 1 2 3 ... 127 		   
u8 OLED_GRAM[128][8];   // 静态声明, 也可动态

//在显存里画点
void OLED_DrawGramPoint(u8 x,u8 y,u8 t)
{
	u8 pos,bx,temp=0;
	if(x>127||y>63)return; //超出范围了不画.
	pos=y/8;
	bx=y%8;
	temp=1<<(bx);
	if(t)OLED_GRAM[x][pos]|=temp;  //填充
	else OLED_GRAM[x][pos]&=~temp; //清空
}

// 在显存里画文字
void OLCD_GramFont(u16 x,u16 y,u8 *font,u8 size,u8 mode)
{
	u8 temp,t,t1;
	u16 y0=y;
	u8 dzk[128];   
	u8 csize=(size/8+((size%8)?1:0))*(size);			//得到字体一个字符对应点阵集所占的字节数	 
	if(size!=12&&size!=16&&size!=24&&size!=32)return;	//不支持的size跳过
	Get_HzMatrix(font,dzk,size);	//得到相应大小的点阵数据, TFTLCD驱动提供
	for(t=0;t<csize;t++)
	{   												   
		temp=dzk[t];			  //得到点阵数据                          
		for(t1=0;t1<8;t1++)
		{
			if(temp&0x80)OLED_DrawGramPoint(x,y,1);
			else if(mode==0)OLED_DrawGramPoint(x,y,0);  // 背景色是否画
			temp<<=1;
			y++;
			if(y>=64)return;	 //Y 超区域了
			if((y-y0)==size)
			{
				y=y0;
				x++;
				if(x>=128)return;	//X 超区域了
				break;
			}
		}  	 
	}  
}

//更新显存到 OLED
void OLED_Refresh_Gram(void)
{
	u8 i,n;		    
	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(OLED_GRAM[n][i]); 
	}   
}

//写字符串
void OLED_Draw_FontString(u8 x, u8 y, u8 *str) {
	u16 x0=x;						  	  
    u8 bHz=0;       // 字符或者中文 
	u8 size = 16;
    while(*str!=0)  // 数据未结束
    { 
        if(!bHz)
        {
	        if(*str>0x80) bHz=1; // 中文 
	        else                 // 字符
	        {      						
				if(*str==13)// 换行
				{         
					// 先跳过
					y+=size;
				    x=x0;
					str++;
				}
				else if(*str==10) {
					y+=size;
				  x=x0;
				}
				else OLED_GramChar(x,y,*str,size,0);// 使用 ascii 点阵写英文和数字
				str++; // 下一个字符或跳过\n
				x+=size/2; // 字符, 为全字的一半 
	        }
        }
		else //中文 
        {     
			bHz=0; 					
			OLCD_GramFont(x,y,str,size,0); // 显示汉字背景色也输出
			str+=2; 
			x+=size; // 下一个汉字偏移	    
        }						 
    }  
		OLED_Refresh_Gram();
}

显示温度和感光度

// 显示温度
void OLED1_Show_TEMP(float temp, u8 *title) {
	u8 s_str[20];

	sprintf((char *)s_str, "湿:----, 温:%.1f", temp);
	OLED_Draw_FontString(0, 0, title);
	OLED_Draw_FontString(0, 16, s_str);
}

// 显示感光
void OLED1_Show_LSENS(u8 lsens) {
	u8 s_str[20];
	sprintf((char *)s_str, "感光值:%hhu", lsens);
	OLED_Draw_FontString(0, 32, s_str);
}

sprintf(tempstr, "温度: %.2f  \r\n", temp);
LCD_ShowFontString(10,460,200,16, 16,(u8*)tempstr, 0);

sprintf((char *)s_str, "感光值:%hhu", lsens);
OLED_Draw_FontString(0, 32, s_str);

效果

在这里插入图片描述

  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Potcutre

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

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

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

打赏作者

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

抵扣说明:

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

余额充值