STM32外设系列—OLED

news2024/9/28 9:27:11

文章目录

  • 一、OLED简介
  • 二、数据手册分析
    • 2.1 供电电压
    • 2.2 引脚定义
    • 2.3 原理图介绍
    • 2.4 数据手册程序
  • 三、IIC通信
    • 3.1 什么是IIC
    • 3.2 IIC通信协议
    • 3.3 IIC主从通信过程
      • 3.3.1 写入数据
      • 3.3.2 读取数据
  • 四、OLED程序设计
    • 4.1 OLED初始化
    • 4.2 OLED控制函数编写
      • 4.2.1 OLED显示开/关程序
      • 4.2.2 OLED显示一组汉字程序
      • 4.2.3 OLED显示一串字符串
      • 4.2.3 OLED显示图片
  • 五、OLED画点/画线

一、OLED简介

OLED是开发时常用的显示器件,这里介绍的是0.96寸的四针脚OLED,IIC控制。
OLED图片

二、数据手册分析

2.1 供电电压

供电电压介绍

供电电压在3V~5V,用3.3V即可。

2.2 引脚定义

OLED引脚定义

2.3 原理图介绍

OLED原理图

I2C通信接口由从地址位DC、I2C总线数据信号SDA(输出SDAOUT/D2输出,SDAIN/D1输入)和I2C总线时钟信号SCL(D0)组成。数据信号和时钟信号都必须连接到上拉电阻器上。

从属地址位(SA0)必须在通过I2C总线传输或接收任何信息之前,先识别该从属地址。设备将响应从地址,后面是从地址位(“SA0”位)和读/写选择位(“R/W#”,具有以下字节格式的位)

字节格式
“SA0”位为从属地址提供了一个扩展位。可以选择“0111100”或“0111101”作为OLED的从属地址。D/C# pin作为SA0进行从属地址的选择”。“收发#”位用于确定I2c总线接口的操作模式。R/W#=1,它处于读取模式。R/W#=0,它处于写模式。

从属地址DC说明
0111 100(0x78)DC = 0默认值
0111 1010(0x7A)DC = 1用户需要切换电阻位置来修改IIC地址

2.4 数据手册程序

数据手册中会给出一些底层程序,可以通过这写程序快速的了解到如何使用。后面的程序设计中会详细介绍这部分,这里就不再做介绍了。

三、IIC通信

3.1 什么是IIC

IIC(Inter-Integrated Circuit)其实是IICBus简称,中文是集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。IIC支持一主多从,主机通过寻址的方式呼叫从机,然后进行数据传输。

I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有从设备的SDA和SLK都接到总线上。

3.2 IIC通信协议

IIC协议中有两种帧,一种是地址帧,用来寻找从设备。一种是数据帧,用来作主从机之间的数据交互。IIC协议还规定了起始信号,终止信号和应答信号。
IIC总线协议

  • 空闲状态
    I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
  • 起始信号
    SCL为高电平期间,SDA信号线由高电平向低电平的变化表示起始信号
  • 终止信号
    SCL为高电平期间,SDA由低电平向高电平的变化表示终止信号

起始信号和终止信号都是由主机发送的,起始信号产生之后,总线处于被占用的状态,在终止信号产生之后,总线就处于空闲状态。

当从机接收完一帧时,会发送一个应答信号。应答信号为低电平时,规定为有效应答(ACK,简称应答位),表示接收器已经成功地接受了该字节应答位为高电平时,规定为非应答信号(NACK),一般表示接收器接收该字节没有成功。

IIC通信协议有自己的数据格式,每一个字节必须保证是8bit长度。数据传送时,先传送最高位,每一个被传送的字节后面都必须跟随1bit的应答位(即每一帧数据一共有9bit)。

3.3 IIC主从通信过程

3.3.1 写入数据

主设备往从设备写入数据需要有下面的过程

  • 主设备发送一个起始信号(START)
  • 主设备在数据线上广播从设备地址
  • 确定数据传输方向(R/W)
  • 等待从设备应答信号(ACK)
  • 主设备发送数据到从设备,从设备接收到后,会返回给主设备一个应答信号,直到主设备发送完数据,或者从设备返回一个NACK信号,表示从设备不再接收数据
  • 数据发送完毕,主设备发送终止信号(STOP)
    主设备往从设备写入数据

3.3.2 读取数据

  • 主设备发送起始信号(START)
  • 主设备在数据线上广播从设备地址
  • 确定数据传输方向(R/W)
  • 等待从设备应答信号(ACK)
  • 从机向主机发送需要读取的数据
  • 主设备每接收到一个字节数据,后面就会跟着向从设备发送一个应答信号
  • 接收完最后一个数据后,主机会发送一个无效应答信号(NACK)
  • 主设备发送终止信号,数据读取完毕
    IIC主设备读取数据

四、OLED程序设计

4.1 OLED初始化

OLED初始化包括两部分,一部分是初始化STM32的GPIO,另一部分是根据数据手册提供的程序初始化OLED。STM32F103ZET6提供了两个IIC接口

SCLSDA
IIC1PB6PB7
IIC2PB10PB11

首先是数据手册提供的IIC相关函数

/*
 *==============================================================================
 *函数名称:IIC_delay
 *函数功能:IIC延时
 *输入参数:无
 *返回值:无
 *备  注:数据手册提供
 *==============================================================================
 */
void IIC_delay (void)
{
	u8 t = 1;
	while (t--);
}
/*
 *==============================================================================
 *函数名称:I2C_Start
 *函数功能:IIC起始信号
 *输入参数:无
 *返回值:无
 *备  注:数据手册提供
 *==============================================================================
 */
void I2C_Start (void)
{
	OLED_SDA_Set();
	OLED_SCL_Set();
	IIC_delay();
	OLED_SDA_Clr();
	IIC_delay();
	OLED_SCL_Clr();
	IIC_delay();
}
/*
 *==============================================================================
 *函数名称:I2C_Stop
 *函数功能:IIC终止信号
 *输入参数:无
 *返回值:无
 *备  注:数据手册提供
 *==============================================================================
 */
void I2C_Stop (void)
{
	OLED_SDA_Clr();
	OLED_SCL_Set();
	IIC_delay();
	OLED_SDA_Set();
}
/*
 *==============================================================================
 *函数名称:I2C_WaitAck
 *函数功能:IIC等待应答
 *输入参数:无
 *返回值:无
 *备  注:数据手册提供
 *==============================================================================
 */
void I2C_WaitAck (void)
{
	OLED_SDA_Set();
	IIC_delay();
	OLED_SCL_Set();
	IIC_delay();
	OLED_SCL_Clr();
	IIC_delay();
}
/*
 *==============================================================================
 *函数名称:Send_Byte
 *函数功能:写入一个字节
 *输入参数:dat:需要写入的数据
 *返回值:无
 *备  注:数据手册提供
 *==============================================================================
 */
void Send_Byte (u8 dat)
{
	u8 i;

	for (i = 0;i < 8;i ++)
	{
		// 发送数据时,从高位依次写入
		if (dat & 0x80)
		{
			OLED_SDA_Set();
		}
		else
		{
			OLED_SDA_Clr();
		}
		IIC_delay();
		OLED_SCL_Set();
		IIC_delay();
		OLED_SCL_Clr();
		
		// dat左移1位
		dat <<= 1;
	}
}
/*
 *==============================================================================
 *函数名称:OLED_WR_Byte
 *函数功能:IIC发送一个字节数据
 *输入参数: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();
}
/*
 *==============================================================================
 *函数名称:Drv_Oled_Init
 *函数功能:初始化OLED
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
 */
void Drv_Oled_Init (void)
{
	// 结构体定义
 	GPIO_InitTypeDef  GPIO_InitStructure;
	
	// 开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	// 初始化GPIO结构体
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;	 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   // 推挽式输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
	// 全部拉高,IIC处于空闲状态
 	GPIO_SetBits(GPIOB,GPIO_Pin_6 | GPIO_Pin_7);	
	
	// 根据数据手册提供的例程,初始化OLED
	delay_ms(200);   // 延时200ms 
	OLED_WR_Byte(0xAE,OLED_CMD);//--display off
	OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
	OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
	OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  
	OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
	OLED_WR_Byte(0x81,OLED_CMD); // contract control
	OLED_WR_Byte(0xFF,OLED_CMD);//--128   
	OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap 
	OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
	OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
	OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
	OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
	OLED_WR_Byte(0x00,OLED_CMD);//	
	OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
	OLED_WR_Byte(0x80,OLED_CMD);//	
	OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
	OLED_WR_Byte(0x05,OLED_CMD);//	
	OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
	OLED_WR_Byte(0xF1,OLED_CMD);//	
	OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
	OLED_WR_Byte(0x12,OLED_CMD);//	
	OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
	OLED_WR_Byte(0x30,OLED_CMD);//	
	OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
	OLED_WR_Byte(0x14,OLED_CMD);//	
	OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
}

下面是相关宏定义

// SCL
#define OLED_SCL_Clr()   GPIO_ResetBits(GPIOB,GPIO_Pin_6)
#define OLED_SCL_Set()   GPIO_SetBits(GPIOB,GPIO_Pin_6)
// SDA
#define OLED_SDA_Clr()   GPIO_ResetBits(GPIOB,GPIO_Pin_7)
#define OLED_SDA_Set()   GPIO_SetBits(GPIOB,GPIO_Pin_7)

#define OLED_CMD   0   //写命令
#define OLED_DATA   1   //写数据

4.2 OLED控制函数编写

数据手册中提供了一些指令,在编写OLED控制函数时可以参考。
数据手册指令

4.2.1 OLED显示开/关程序

根据数据手册描述,发送指令“1010 111x0”,其中x0为0时,显示关闭,x0为1时,显示开启。因此,显示开关程序如下

/*
 *==============================================================================
 *函数名称:Med_Oled_Display_On
 *函数功能:开启OLED显示
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
 */  
void Med_Oled_Display_On(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);   // 设置充电泵启用/禁用
	OLED_WR_Byte(0X14,OLED_CMD);   // 设置(0x10)禁用
	OLED_WR_Byte(0XAF,OLED_CMD);   // DISPLAY ON
}
/*
 *==============================================================================
 *函数名称:Med_Oled_Display_Off
 *函数功能:关闭OLED显示
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
 */  
void OLED_Display_Off(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);   // 设置充电泵启用/禁用
	OLED_WR_Byte(0X10,OLED_CMD);   // 设置高列地址
	OLED_WR_Byte(0XAE,OLED_CMD);   // DISPLAY OFF
}	

4.2.2 OLED显示一组汉字程序

想要显示汉字,需要先创建字库。汉字取模使用PCtoLCD2002完美版,取模时的配置已经标注

// 汉字字模数据结构定义
struct Cn16CharTypeDef   // 汉字字模数据结构 
{
	unsigned char Index[2];   // 汉字内码索引,一个汉字占两个字节	
	unsigned char Msk[32];   // 点阵码数据(16*16/8) 
};

// 汉字取模要求
// 阴码,逆向,列行式,16X16
struct Cn16CharTypeDef const CnChar16x16[]=
{
"太",0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xFF,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,
0x80,0x80,0x40,0x20,0x10,0x0C,0x13,0x60,0x03,0x0C,0x10,0x20,0x40,0x80,0x80,0x00,/*"太",0*/

"陈",0x00,0xFE,0x22,0x5A,0x86,0x08,0x88,0x68,0x18,0x0F,0xE8,0x08,0x08,0x08,0x08,0x00,
0x00,0xFF,0x04,0x08,0x07,0x20,0x11,0x0D,0x41,0x81,0x7F,0x01,0x05,0x09,0x30,0x00,/*"陈",1*/

"抱",0x10,0x10,0x10,0xFF,0x90,0x20,0x10,0xEC,0x27,0x24,0x24,0xE4,0x04,0xFC,0x00,0x00,
0x02,0x42,0x81,0x7F,0x00,0x00,0x00,0x3F,0x42,0x42,0x4A,0x53,0x48,0x47,0x70,0x00,/*"抱",2*/

"不",0x00,0x02,0x02,0x02,0x02,0x82,0x42,0xF2,0x0E,0x42,0x82,0x02,0x02,0x02,0x00,0x00,
0x10,0x08,0x04,0x02,0x01,0x00,0x00,0xFF,0x00,0x00,0x00,0x01,0x02,0x0C,0x00,0x00,/*"不",3*/

"动",0x40,0x44,0xC4,0x44,0x44,0x44,0x40,0x10,0x10,0xFF,0x10,0x10,0x10,0xF0,0x00,0x00,
0x10,0x3C,0x13,0x10,0x14,0xB8,0x40,0x30,0x0E,0x01,0x40,0x80,0x40,0x3F,0x00,0x00,/*"动",4*/

};

汉字显示函数如下

/*
 *==============================================================================
 *函数名称:Med_Oled_ShowCHinese16x16
 *函数功能:显示一组16*16的汉字
 *输入参数:x:横坐标;y:纵坐标(0~3);cn:要显示的汉字
 *返回值:无
 *备  注:无
 *==============================================================================
 */ 
void Med_Oled_ShowCHinese16x16 (u8 x,u8 y,u8 *cn)
{      			    
	u8 i,num;
	
	while (*cn != '\0')
	{
		// 扫描字库
		// 这里的100,是字库所能容纳的汉字上限,可修改
		for (num = 0;num < 100;num ++)
		{
			// 如果找到匹配的汉字
			if ((CnChar16x16[num].Index[0]==*cn)
						 &&(CnChar16x16[num].Index[1]==*(cn+1)))
			{
				// 显示前16个点
				Med_Oled_Set_Pos(x,y);	
				for(i=0;i<16;i++)
				{
					OLED_WR_Byte(CnChar16x16[num].Msk[i],OLED_DATA);
				}
				// 显示后16个点
				Med_Oled_Set_Pos(x,y+1);	
				for(i=16;i<32;i++)
				{
					OLED_WR_Byte(CnChar16x16[num].Msk[i],OLED_DATA);
				}
			}
		}
		cn += 2;
		x += 16;   //若改字号,需要改
	}	
}

当需要显示汉字时,只需要写下面的程序,即可直接显示一组汉字

Med_Oled_ShowCHinese16x16(1,2,"太陈抱不动");   // 显示一组汉字

4.2.3 OLED显示一串字符串

要显示字符串,也要有对应的字库,这里提供了8号和16号字库,就不再列出了。想要显示一串字符串,需要先编写显示字符函数

/*
 *==============================================================================
 *函数名称:Med_Oled_ShowChar
 *函数功能:显示一个字符
 *输入参数:x:横坐标;y:纵坐标;chr:要显示的字符串;Char_Size:大小(8/16)
 *返回值:无
 *备  注:无
 *==============================================================================
 */ 
void Med_Oled_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{      	
	u8 c=0,i=0;	
	c=chr-' ';//得到偏移后的值			
	if(x > Max_Column-1){x=0;y=y+2;}
	if(Char_Size ==16)
	{
		Med_Oled_Set_Pos(x,y);	
		for(i=0;i<8;i++)
		OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
		Med_Oled_Set_Pos(x,y+1);
		for(i=0;i<8;i++)
		OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
	}
	else
	{	
		Med_Oled_Set_Pos(x,y);
		for(i=0;i<6;i++)
		OLED_WR_Byte(F6x8[c][i],OLED_DATA);
	}
}

显示一串字符串函数如下

/*
 *==============================================================================
 *函数名称:Med_Oled_ShowString
 *函数功能:显示一串字符串
 *输入参数:x:横坐标;y:纵坐标;chr:要显示的字符串;Char_Size:大小(8/16)
 *返回值:无
 *备  注:无
 *==============================================================================
 */ 
void Med_Oled_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
{
	while (*chr!='\0')
	{
		Med_Oled_ShowChar(x,y,*chr,Char_Size);
		x+=8;
		if(x>120)
		{
			x=0;
			y+=2;
		}
		chr++;
	}
}

需要显示一串字符串时,添加下面程序

Med_Oled_ShowString(2,6,"ertu-20230621",8);   // 在OLED上显示字符串

4.2.3 OLED显示图片

下面提供了显示图片的函数

/*
 *==============================================================================
 *函数名称:Med_Oled_DrawBMP
 *函数功能:显示一张BMP图片
 *输入参数:x0:起始横坐标;y:起始纵坐标;x1:终止横坐标;y1:终止纵坐标;
            BMP[]:要显示的图片
 *返回值:无
 *备  注:无
 *==============================================================================
 */ 
void Med_Oled_DrawBMP(u8 x0, u8 y0, u8 x1, u8 y1,u8 BMP[]) 
{ 	
 u32 j=0;
 u8 x,y;
  
  if (y1%8==0) 
	{
		y = y1 / 8;   
	}   
  else
	{
		y = y1 / 8 + 1;
	}
	for (y = y0;y < y1;y ++)
	{
		Med_Oled_Set_Pos(x0,y);
    for(x = x0;x < x1;x ++)
	    {      
	    	OLED_WR_Byte(BMP[j++],OLED_DATA);	    	
	    }
	}
} 

下面是图片取模后的存储文件,其中标注了取模软件,以及取模时的配置

#ifndef __BMP_H
#define __BMP_H

// 图片取模时,首先将图片另存为.bmp格式
// 用Image2Lcd软件取模
// 扫描模式设置为数据水平,字节垂直
// 输出灰度为单色
// 40*40
// 只勾选字节内像素数据反序
unsigned char BMP1[] =
 { /* 0X22,0X01,0X28,0X00,0X28,0X00, */
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X80,
0XC0,0X60,0X30,0X10,0X10,0X30,0X20,0X20,0X20,0X00,0X40,0X40,0X40,0X40,0X00,0X00,
0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0XC0,0X60,0X30,0X18,0X0C,0X06,0X03,0X01,0X08,0X04,0X02,0X12,0X02,0X04,0X24,0X24,
0X24,0X20,0X08,0X08,0X28,0X10,0X00,0X00,0X80,0X40,0X71,0X09,0XC7,0X00,0X00,0X00,
0X00,0X00,0X00,0XE0,0X18,0X04,0X82,0X40,0X00,0X80,0X80,0X80,0X80,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XC0,0X60,0X30,0X18,0X8C,0X44,0X11,
0X08,0X87,0X60,0X30,0X0F,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0X20,0X43,0X44,0X00,
0X90,0X90,0X90,0X20,0X20,0X20,0X41,0X41,0X03,0X82,0X82,0X80,0X84,0X04,0X04,0X42,
0X21,0X10,0X84,0X06,0X23,0X10,0X08,0X02,0X01,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0X00,0X02,0X02,
0X02,0X02,0X00,0X04,0X04,0X0C,0X08,0X0C,0X06,0X03,0X01,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,};

#endif

主程序中添加如下程序,最终显示结果如下

Med_Oled_DrawBMP(10,1,50,6,BMP1);   // 显示图片

OLED显示图片

五、OLED画点/画线

使用OLED时,也常用到画点或者画线,这里给出画点和画线的函数。

/*
 *==============================================================================
 *函数名称:Med_Oled_Refresh_Gram
 *函数功能:更新缓存显示内容
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
 */ 
u8 OLED_GRAM[128][8];
void Med_Oled_Refresh_Gram(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);
  }
}
/*
 *==============================================================================
 *函数名称:Med_Oled_DrawPoint
 *函数功能:画点
 *输入参数:x:横坐标;y:纵坐标;t:清除(0)/填充(1)
 *返回值:无
 *备  注:OLED最下面是y = 0
 *==============================================================================
 */ 
void Med_Oled_DrawPoint(u8 x,u8 y,u8 t)
{
  u8 pos,bx,temp=0;
  if(x>127||y>63)return ;
  pos=7-y/8;
  bx=y%8;
  temp=1<<(7-bx);
  if(t)OLED_GRAM[x][pos]=temp;
  else OLED_GRAM[x][pos]&=~temp;
	// 更新缓存显示内容
	Med_Oled_Refresh_Gram(); 
}
/*
 *==============================================================================
 *函数名称:Med_Oled_DrawLine
 *函数功能:画线
 *输入参数:x1:起始点横坐标;y1:起始点纵坐标;x2:结束点横坐标;
            y2:结束点纵坐标;x:0~128;y:0~64
 *返回值:无
 *备  注:OLED最下面是y = 0
 *==============================================================================
 */ 
void Med_Oled_DrawLine(u8 x1, u8 y1, u8 x2,u8 y2)
{
	unsigned int t; 
	int xerr=0,yerr=0,delta_x,delta_y,distance; 
	int incx,incy,uRow,uCol; 
	delta_x=x2-x1; //计算坐标增量 
	delta_y=y2-y1; 
	uRow=x1; 
	uCol=y1; 
	if(delta_x>0)incx=1; //设置单步方向 
	else if(delta_x==0)incx=0;//垂直线 
	else {incx=-1;delta_x=-delta_x;} 
	if(delta_y>0)incy=1; 
	else if(delta_y==0)incy=0;//水平线 
	else{incy=-1;delta_y=-delta_y;} 
	if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 
	else distance=delta_y; 
	for(t=0;t<=distance+1;t++ )//画线输出 
	{  
		Med_Oled_DrawPoint(uRow,uCol,1);//画点 
		xerr+=delta_x ; 
		yerr+=delta_y ; 
		if(xerr>distance) 
		{ 
			xerr-=distance; 
			uRow+=incx; 
		} 
		if(yerr>distance) 
		{ 
			yerr-=distance; 
			uCol+=incy; 
		} 
	}
	// 更新缓存显示内容
	Med_Oled_Refresh_Gram();  
}  

main函数添加如下代码

Med_Oled_DrawPoint(10,20,1);   // 画点
Med_Oled_DrawLine(0,30,100,30);   // 画线

显示内容如下
OLED画点画线函数展示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/671303.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ECCV2022 多目标跟踪(MOT)汇总

一、《Towards Grand Unification of Object Tracking》 作者: Bin Yan1⋆, Yi Jiang2,†, Peize Sun3, Dong Wang1,†,Zehuan Yuan2, Ping Luo3, and Huchuan Lu School of Information and Communication Engineering, Dalian University of Technology, China 2 ByteDance …

企业级开发环境配置(JDK、tomcat、Maven、Git、IDEA个性化界面的设定)

企业级开发环境配置&#xff08;JDK、tomcat、Maven、Git、IDEA个性化界面的设定&#xff09; 一、JRE,JDK8安装和环境变量配置1. 进入Oracle官网进行jdk8安装包的下载2. 选择安装路径&#xff0c;安装路径不要出现中文以及空格3. 环境变量的配置4. 安装验证 二、Tomcat 安装和…

性能测试面试题:如何测试App性能?(面试必问)

为什么要做App性能测试&#xff1f; 如果APP总是出现卡顿或网络延迟的情况&#xff0c;降低了用户的好感&#xff0c;用户可能会抛弃该App&#xff0c;换同类型的其他应用。如果APP的性能较好&#xff0c;用户体验高&#xff0c;使用起来丝滑顺畅&#xff0c;那该应用的用户粘…

Nginx入门?看这一篇就够了

Nginx&#xff1f;看这一篇就够了 前言Nginx介绍没有好用的&#xff1f;那就自己做一个&#xff01;Nginx的发展历程Nginx的特性&#xff08;为什么要用Nginx&#xff09; 异步事件驱动同步事件驱动同步事件驱动的问题 异步事件驱动异步非阻塞与同步非阻塞并发和并行I/O多路复用…

【数据关联】基于Patch的对应特征关联,关联当前帧->参考帧,帧间追踪

帧间追踪与数据关联 1. WarpPixelWise(求当前帧特征点位置)1.1 函数功能1.2 函数输入输出1.3 算法步骤 2. GetWarpMatrixAffine(计算 当前帧->参考帧 仿射变换矩阵)2.1 函数功能2.2 函数输入输出2.3 算法步骤 3. GetWarpMatrixAffine(计算 当前帧->参考帧 仿射变换矩阵)3…

modbus TCP协议讲解及实操

具体讲解 前言正文modbus tcp主机请求数据基本讲解Modbus Poll工具简单使用讲解 modbus tcp从机响应数据Modbus Slave工具简单使用讲解 前言 关于modbus tcp从0到1的讲解&#xff0c;案例结合讲解&#xff0c;详细了解整个modbus的可以参考这个&#xff1a;详解Modbus通信协议…

【吃透网络安全】2023软考网络管理员考点网络安全(一)安全基础篇

涉及知识点 软考网络管理员&#xff0c;软考网络管理员常考知识点&#xff0c;软考网络管理员网络安全&#xff0c;网络管理员考点汇总。 后面还有更多续篇希望大家能给个赞哈&#xff0c;这边提供个快捷入口&#xff01; 第一节 网络管理员考点网络安全&#xff08;1&#…

【广州华锐互动】钢厂轧钢事故3D虚拟体验还原真实事故场景

由于钢厂生产过程中涉及到高温、高压、高负荷等危险因素&#xff0c;一旦出现操作不当、设备故障等问题&#xff0c;就可能导致严重的事故。因此&#xff0c;对于钢厂员工来说&#xff0c;接受事故教育、了解安全知识非常重要&#xff0c;可以提高他们的安全意识&#xff0c;避…

大数据行业对学历要求高么

《2020中国大数据产业发展白皮书》显示&#xff0c;2019年中国大数据产业规模达5397亿元&#xff0c;同比增长23.1%&#xff0c;随后稳定增长&#xff0c;预计到2022年将突破万亿元。 根据LinkedIn、赛迪智库、拉勾网等机构的统计结果&#xff0c;大数据时代下的数据人才总体缺…

【软考程序员学习笔记】——程序设计语言

目录 &#x1f34a;一、常见的程序设计语言 &#x1f34a;二、程序设计语言组成 &#x1f34a;三、后缀表达式 &#x1f34a;四、传值调用和传址调用 &#x1f34a;五、语言处理程序 &#x1f34a;六、解释程序 &#x1f34a;七、链接程序 &#x1f34a;八、编译程序 &…

国产替代FT232RL-USB到UART桥接控制器 GP232RNL

GP232RNL是一款高度集成的USB到UART桥接控制器&#xff0c;提供了一种简单的解决方案&#xff0c;可以使用最少的元器件和PCB空间&#xff0c;将RS232接口转换为USB接口。GP232RNL包括一个USB 2.0全速功能控制器、USB收发器、振荡器、EEPROM和带有完整的调制解调器控制信号的异…

Java GUI开发的几个小工具:apk/aab签名,验证签名,aab转apk

平时经常给apk/aab签名&#xff0c;验证签名&#xff0c;aab转apk等操作&#xff0c;每次输入命令行十分繁琐。于是利用JAVA GUI简单开发了几个jar包界面化工具&#xff0c;提供给大家一起使用。 工具功能JarSignerTool.jar为apk/aab签名ApkSignerTool.jar为apk签名AppSignVer…

Cloud Studio 浏览器插件来啦

当谈到Cloud Studio浏览器插件的优势时&#xff0c;最显著的就是它的便捷性。通过安装Cloud Studio浏览器插件&#xff0c;用户可以在浏览器中直接打开Cloud Studio的开发环境&#xff0c;无需切换到其他应用程序&#xff0c;从而提高了开发效率。 另一个优势是插件对于Github…

Logstash入门简介

目录 Logstash简介介绍用途部署安装测试配置详解输入过滤输出 读取自定义日志日志结构编写配置文件输出到Elasticsearch Logstash简介 介绍 Logstash是一个开源的服务器端数据处理管道&#xff0c;能够同时从多个来源采集数据&#xff0c;转换数据&#xff0c;然后将数据发送到…

了解一下EPC模式和它的优势

目录 什么是EPCEPC的优势有哪些&#xff1f;BT、BOT、EPC分别是什么模式&#xff1f;总结 什么是EPC EPC是Engineering&#xff08;工程&#xff09;&#xff1a;代表设计、采购和施工总承包。Procurement&#xff08;采购&#xff09;&#xff1a;代表采购和物资管理。Constru…

Stable Diffusion提示词总结

提示词基本语法 一、提示词类别 1、内容型提示词 人物及主体特征 服饰穿搭 white dress 发型发色 blonde hair&#xff0c;long hair 五官特征 small eye&#xff0c;big mouth 面部表情 smiling 肢体动作 stretching arms beautiful detailed eyes 美丽细致的眼睛 highl…

数字化如何推动快消品企业实现营销变革

近几年&#xff0c;不确定性在各行各业上演。尤其伴随新一代信息技术的快速发展&#xff0c;消费者的需求和购买渠道也在不断变化。这就要求企业需要通过对消费者潜在需求进行更加深度的挖掘&#xff0c;为消费者提供“更佳的体验”&#xff0c;从而释放消费能力。 在这样的大背…

HTTP协议中的GET和POST接口测试的区别

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言HTTP协议基础GET请…

CVPR2023中的数据集工作(共46篇)

本文搜集了CVPR2023中所有的以数据集发布为主的工作&#xff0c;共搜集到46篇。所有标题都附带文章超链接&#xff0c;请君享用&#xff5e; An Image Quality Assessment Dataset for PortraitsLOGO: A Long-Form Video Dataset for Group Action Quality AssessmentTowards …

C++学习 数据类型

数据类型存在的意义&#xff1a; 给变量分配合适的内存空间&#xff0c;避免资源浪费。 整型&#xff1a; 整型变量表示的是整数类型的数据 long类型 在 windows 中4字节 linux 中 32位4字节 64位8字节&#xff0c;占用空间的不同&#xff0c;可以表示的取值范围就越广&…