基于stm32的oled显示

目录

1.显示原理

 2.接口配置

8080并行接口模式

spi四线

3.程序控制


1.显示原理

基于stm32的oled显示(以ALINETEK0.96寸OLED模块为例)

ALINETEK0.96寸OLED模块由SSD1306驱动芯片控制:

SSD1306的显存总共为128*64bit大小,分为八页,每页为128个字节,共计128*68位,以此对应屏幕的168*64像素,将显存的各位置0或置1即可控制像素点的亮灭。

使用时在stm32内建立一个缓存,大小为128*8字节,在每次修改时先修改stm32的缓存,在修改完成后,一次性地将stm32上的缓存写入OLED的GRAM来更新显示

 2.接口配置

单片机与SSD1306的通信可以采用8080并口、6800并口、SPI、IIC四种方式,这里介绍8080与SPI两种

8080并行接口模式

8080 并行接口被广泛应用于各类液晶显示器, ALIENTEK OLED 模块也提供了这种接口,使得 MCU 可以快速的访问 OLED。
8080 接口方式需要如下一些信号线:
CS: OLED 片选信号。
WR:向 OLED 写入数据。
RD:从 OLED 读取数据。
D[7: 0]: 8 位双向数据线。
RST(RES):硬复位 OLED。
DC:命令/数据标志(0,读写命令; 1,读写数据)。

读数据:在 RD 的上升沿, 使数据锁存到数据线(D[7: 0])上;
写数据:在 WR 的上升沿,使数据写入到 SSD1306 里面;

在正点原子例程中对8080接口的初始化如下

#if OLED_MODE==1		//使用8080并口模式		
	
	//GPIO初始化设置      
    GPIO_Initure.Pin=GPIO_PIN_4;         	//PA4
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;	//推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;        	//上拉
    GPIO_Initure.Speed=GPIO_SPEED_FAST;   	//快速
    HAL_GPIO_Init(GPIOA,&GPIO_Initure);   	//初始化
	
    //PB6,7
    GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7;	
	HAL_GPIO_Init(GPIOB,&GPIO_Initure);//初始化

    //PC6,7,8,9,11
    GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_11;	
	HAL_GPIO_Init(GPIOC,&GPIO_Initure);//初始化	
  
    //PD6,7
	GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7;	
	HAL_GPIO_Init(GPIOD,&GPIO_Initure);//初始化	
	
    //PE5,6
	GPIO_Initure.Pin=GPIO_PIN_5|GPIO_PIN_6;	
	HAL_GPIO_Init(GPIOE,&GPIO_Initure);//初始化	
	
	//PG15
	GPIO_Initure.Pin=GPIO_PIN_15;	
	HAL_GPIO_Init(GPIOG,&GPIO_Initure);//初始化	
	
	OLED_WR=1;
  	OLED_RD=1; 
#else					//使用4线SPI 串口模式

8080写字节:

#if OLED_MODE==1	//8080并口
//通过拼凑的方法向OLED输出一个8位数据
//data:要输出的数据
void OLED_Data_Out(u8 data)
{
	u16 dat=data&0X0F;
	GPIOC->ODR&=~(0XF<<6);		//清空6~9
	GPIOC->ODR|=dat<<6;			//D[3:0]-->PC[9:6]
    
    GPIOC->ODR&=~(0X1<<11);		//清空11
    GPIOC->ODR|=((data>>4)&0x01)<<11;
    
    GPIOB->ODR&=~(0X1<<6);		//清空6
    GPIOB->ODR|=((data>>5)&0x01)<<6;
    
    GPIOE->ODR&=~(0X3<<5);		//清空5,6
    GPIOE->ODR|=((data>>6)&0x01)<<5;
    GPIOE->ODR|=((data>>7)&0x01)<<6;
} 
//向SSD1306写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
{
	OLED_Data_Out(dat);	
 	OLED_RS=cmd;
	OLED_CS=0;	
	OLED_WR=0;	  
	OLED_WR=1;   
	OLED_CS=1;   
	OLED_RS=1;   
} 	   

spi四线

SPI介绍:STM32 SPI介绍及CubeMX配置

在正点原子例程中对SPI接口的初始化如下

#else					//使用4线SPI 串口模式

	//GPIO初始化设置      
    GPIO_Initure.Pin=GPIO_PIN_7;         	//PB7
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;	//推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;        	//上拉
    GPIO_Initure.Speed=GPIO_SPEED_FAST;   	//高速
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);   	//初始化
	
    //PC6,7
    GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7;	
	HAL_GPIO_Init(GPIOC,&GPIO_Initure);//初始化

    //PD6
    GPIO_Initure.Pin=GPIO_PIN_6;	
	HAL_GPIO_Init(GPIOD,&GPIO_Initure);//初始化	
	
	//PG15
    GPIO_Initure.Pin=GPIO_PIN_15;	
	HAL_GPIO_Init(GPIOG,&GPIO_Initure);//初始化
	
	OLED_SDIN=1;
	OLED_SCLK=1;
#endif

SPI写字节:

//向SSD1306写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
{	
	u8 i;			  
	OLED_RS=cmd; //写命令 
	OLED_CS=0;		  
	for(i=0;i<8;i++)
	{			  
		OLED_SCLK=0;
		if(dat&0x80)OLED_SDIN=1;
		else OLED_SDIN=0;
		OLED_SCLK=1;
		dat<<=1;   
	}				 
	OLED_CS=1;		  
	OLED_RS=1;   	  
} 

3.程序控制

通过指令可以修改OLED对比度、显示开关及修改缓存

SSD1306有下列指令:

初始化OLED过程为 复位SSD1306→驱动IC初始化代码→开启显示→请0显存→开始显示

初始化完成后,修改单片机内缓存数据并上传至SSD1306即可更新更新OLED显示画面

例程中定义了以下函数可供使用:

//OLED控制用函数
void OLED_WR_Byte(u8 dat,u8 cmd);	    
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Refresh_Gram(void);		   
							   		    
void OLED_Init(void);
void OLED_Clear(void);
void OLED_DrawPoint(u8 x,u8 y,u8 t);
void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size);
void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size);

用以上函数修改缓存后调用OLED_Refresh_Gram()函数就可以更新OLED画面

  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是基于STM32OLED显示屏的年月日显示代码: ```c #include "stm32f10x.h" #include "oled.h" #include "stdlib.h" #include "stdio.h" #include "delay.h" #include "iic.h" #define I2C_Speed 400000 #define I2C1_SLAVE_ADDRESS7 0x78 u8 year,month,day,week; u8 hour,minute,second; void RTC_Configuration(void); void I2C_Configuration(void); void TIM_Configuration(void); void NVIC_Configuration(void); void OLED_Init(void); void OLED_ShowStr(u8 x,u8 y, u8 ch[], u8 TextSize); void OLED_ShowNum(u8 x,u8 y, u32 num, u8 len, u8 TextSize); void OLED_ShowTime(u8 x,u8 y); void OLED_ShowDate(u8 x,u8 y); void OLED_ShowWeek(u8 x,u8 y); int main(void) { NVIC_Configuration(); TIM_Configuration(); OLED_Init(); RTC_Configuration(); I2C_Configuration(); while(1) { OLED_ShowTime(0,0); OLED_ShowDate(0,2); OLED_ShowWeek(0,4); } } void RTC_Configuration(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); PWR_BackupAccessCmd(ENABLE); RCC_LSEConfig(RCC_LSE_ON); while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET); RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); RCC_RTCCLKCmd(ENABLE); RTC_WaitForSynchro(); RTC_WaitForLastTask(); RTC_SetPrescaler(32767); RTC_WaitForLastTask(); RTC_ITConfig(RTC_IT_SEC, ENABLE); RTC_WaitForLastTask(); } void I2C_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; I2C_InitTypeDef I2C_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); I2C_DeInit(I2C1); I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = I2C1_SLAVE_ADDRESS7; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = I2C_Speed; I2C_Init(I2C1, &I2C_InitStructure); I2C_Cmd(I2C1, ENABLE); } void TIM_Configuration(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructure.TIM_Period = 999; TIM_TimeBaseStructure.TIM_Prescaler = 7199; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); TIM_Cmd(TIM2, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); EXTI_ClearITPendingBit(EXTI_Line17); EXTI_InitStructure.EXTI_Line = EXTI_Line17; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); } void OLED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_10 | GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); OLED_InitGpio(); OLED_InitI2c(); OLED_InitDev(); OLED_Fill(0x00); OLED_Refresh_Gram(); } void OLED_ShowStr(u8 x,u8 y, u8 ch[], u8 TextSize) { u8 c = 0,i = 0,j = 0; switch(TextSize) { case 1: while (ch[j] != '\0') { c = ch[j] - 32; if(x>128-6) { x=0; y++; } OLED_ShowChar(x,y,c,TextSize); x+=6; j++; } break; case 2: while (ch[j] != '\0') { c = ch[j] - 32; if(x>128-12) { x=0; y++; } OLED_ShowChar(x,y,c,TextSize); x+=12; j++; } break; } } void OLED_ShowNum(u8 x,u8 y, u32 num, u8 len, u8 TextSize) { u8 t,temp; u8 enshow=0; for(t=0;t<len;t++) { temp=(num/10^(len-t-1))%10; if(enshow==0&&t<(len-1)) { if(temp==0) { OLED_ShowChar(x+(TextSize/2)*t,y,' ',TextSize); continue; } else enshow=1; } OLED_ShowChar(x+(TextSize/2)*t,y,temp+'0',TextSize); } } void OLED_ShowTime(u8 x,u8 y) { RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure); hour = RTC_TimeStructure.RTC_Hours; minute = RTC_TimeStructure.RTC_Minutes; second = RTC_TimeStructure.RTC_Seconds; OLED_ShowNum(x,y,hour,2,1); OLED_ShowChar(x+2*6,y,':',1); OLED_ShowNum(x+3*6,y,minute,2,1); OLED_ShowChar(x+5*6,y,':',1); OLED_ShowNum(x+6*6,y,second,2,1); } void OLED_ShowDate(u8 x,u8 y) { RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure); year = RTC_DateStructure.RTC_Year; month = RTC_DateStructure.RTC_Month; day = RTC_DateStructure.RTC_Date; OLED_ShowNum(x,y,year,4,1); OLED_ShowChar(x+4*6,y,'/',1); OLED_ShowNum(x+5*6,y,month,2,1); OLED_ShowChar(x+7*6,y,'/',1); OLED_ShowNum(x+8*6,y,day,2,1); } void OLED_ShowWeek(u8 x,u8 y) { RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure); week = RTC_DateStructure.RTC_WeekDay; switch(week) { case 1: OLED_ShowStr(x,y,"Monday",1); break; case 2: OLED_ShowStr(x,y,"Tuesday",1); break; case 3: OLED_ShowStr(x,y,"Wednesday",1); break; case 4: OLED_ShowStr(x,y,"Thursday",1); break; case 5: OLED_ShowStr(x,y,"Friday",1); break; case 6: OLED_ShowStr(x,y,"Saturday",1); break; case 7: OLED_ShowStr(x,y,"Sunday",1); break; } } ``` 请注意,这只是一个示例代码,实际使用时需要根据自己的硬件和软件环境进行适当的修改。同时需要注意的是,本代码仅提供参考,对于代码的正确性和安全性,需读者自行进行检验和验证。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值