这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 镜子里的屏幕——显示功能讲解

共1条 1/1 1 跳转至

镜子里的屏幕——显示功能讲解

助工
2018-09-18 14:33:29     打赏

大家好,这次讲一下RTC时钟和OLED驱动函数,Let’s 学习吧!

一.RTC

1.1.RTC概述

实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。

RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。

简单来说就是一个STM32系统自带的时钟。RTCCLK 时钟源可以由 HSE LSE LSI 时钟提供。STM32F0 RTC 模块和 F1 RTC 模块最大区别在于 F0 模块中有“DATE”和“TIME”寄存器,也就是可以直接读取寄存器里面的值,而 F1 是秒计数寄存器的值,需要通过相关算法下才能得到时间的值。

2345截图20180730163639.png

1.2软件设计

//RTC初始化
void RTC_Initializes(void)
{
  RTC_InitTypeDef RTC_InitStructure;
  RTC_DateTimeTypeDef RTC_DateTimeStructure;
  PWR_BackupAccessCmd(ENABLE);                   //允许操作RTC
  if(RTC_ReadBackupRegister(RTC_BKP_DR0) != RTC_FLAG_BKP)
  {
    RTC_Configuration();                         //配置RTC
    RTC_InitStructure.RTC_AsynchPrediv = AsynchPrediv;
    RTC_InitStructure.RTC_SynchPrediv = SynchPrediv;
    RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
    if(RTC_Init(&RTC_InitStructure) == ERROR)
    {
      while(1);          //初始化失败
    }
 
    RTC_DateTimeStructure.Hour = 10;
    RTC_DateTimeStructure.Minute = 57;
    RTC_DateTimeStructure.Second = 0;
    RTC_SetDateTime(RTC_DateTimeStructure);
    RTC_WriteBackupRegister(RTC_BKP_DR0, RTC_FLAG_BKP);
  }
  else
  {
 #ifdef RTC_CLOCK_SOURCE_LSI
    RCC_LSICmd(ENABLE);
 #endif
    RTC_WaitForSynchro();  
  }
}
 
// RTC时间矫正
//RTC_OK ----------------- 成功
//RTC_ERR ---------------- 错误
RTC_RESULT RTC_TimeRegulate(RTC_DateTimeTypeDef RTC_DateTimeStructure)
{
  RTC_TimeTypeDef RTC_TimeStructure;
 
  RTC_TimeStructure.RTC_H12 = RTC_H12_AM;
  RTC_TimeStructure.RTC_Hours = RTC_DateTimeStructure.Hour;
  RTC_TimeStructure.RTC_Minutes = RTC_DateTimeStructure.Minute;
  RTC_TimeStructure.RTC_Seconds = RTC_DateTimeStructure.Second;
 
  if(RTC_SetTime(RTC_Format_BIN, &RTC_TimeStructure) == SUCCESS)
  {
    return RTC_OK;
  }
  else
  {
    return RTC_ERR;
  }
}
 
//RTC时间设置
//RTC_OK ----------------- 成功
//RTC_ERR ---------------- 错误
RTC_RESULT RTC_SetDateTime(RTC_DateTimeTypeDef RTC_DateTimeStructure)
{
 
  if(RTC_ERR == RTC_TimeRegulate(RTC_DateTimeStructure))
  {
    return RTC_ERR;
  }
 
  return RTC_OK;
}
 
//读取RTC时间
void RTC_GetDateTime(RTC_DateTimeTypeDef *RTC_DateTimeStructure)
{
  RTC_TimeTypeDef RTC_TimeStructure;
 
  RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);
  RTC_DateTimeStructure->Hour = RTC_TimeStructure.RTC_Hours;
  RTC_DateTimeStructure->Minute = RTC_TimeStructure.RTC_Minutes;
  RTC_DateTimeStructure->Second = RTC_TimeStructure.RTC_Seconds;
}


还有强调一下,RTC的时钟源可以有很多种,比如HSE LSE LSI等, LSE 时钟属于备份域的,但LSI 时钟不属于备份域时钟,因此:

LSE 被选为 RTC 时钟:只要维持 VBAT 正常供电,即使 VDD 掉电, RTC 仍会继续工作。

LSI 选为 RTC 时钟:当 VDD 掉电时, RTC 处于不定的状态。

在这个项目中需要选择时钟源由LSI 时钟提供,因为LSE需要外接32.768kHZ晶振和纽扣电池供电,恰巧没有…LSE的好处是可以做到掉电放丢失和时间精度高。经过测试,选用LSI时,15分钟时间误差为6秒左右,选用LSE时半小时0误差。所以有兴趣的可以搞一下这个。


如图所示。

9.jpg


通过这四个函数就可以设置RTC时钟时间,再通过OLED显示或串口打印出来,就能得到相应的时钟。

下面在简单说一下OLED的问题

. OLED显示屏

2.1 OLED概述

OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display OELD)。

优势:主动发光的特性使 OLED 几乎没有视角限制,视角一般可达到 170 度,具

有较宽的视角,从侧面也不会失真。OLED 采用有机发光原理,所需材料很少,制作上比采用液体发光的液晶工序少,液晶显示屏少 3 道工序,成本大幅降低。

具有多种接口方式,该模块提供了总共 5 种接口包括: 6800 8080 两种并行接口方式、 3线或4线的SPI接口,IIC接口方式。

本次DIY用到的是I2C通信的OLED显示屏,只需操作两个IO口,更加简单。

显示尺寸为0.96寸,分辨率为128*64

OLED相当于64128列点阵,每个像素点,0点亮,1熄灭

OLED将纵向64行分为8,每页8行。

原理图如图所示

7.jpg


2.2 硬件设计

      SCL —— PB8

      SDA——PB9

    VCC——VCC

    GND——GND

2.3软件设计

//写命令
void WriteCmd(unsigned char IIC_Cmd)
{
  IIC_Start();
  Write_OneByte(0x78);
         Write_OneByte(0x00);
         Write_OneByte(IIC_Cmd);
         IIC_Stop();
}
//写数据
void WriteDat(unsigned char IIC_Dat)
{
  IIC_Start();
  Write_OneByte(0x78);
         Write_OneByte(0x40);
         Write_OneByte(IIC_Dat);
         IIC_Stop();
}
//设置坐标
void OLED_SetPos(unsigned char x,unsigned char y)
{
 WriteCmd(0xb0+y);
 WriteCmd(((x&0xf0)>>4)|0x10);
 WriteCmd((x&0x0f)|0x01);
}
//OLED全屏填充
void OLED_Fill(unsigned char fill_Data)
{
 unsigned char m,n;
         for(m=0;m<8;m++)
         {
          WriteCmd(0xb0+m);
          WriteCmd(0x00);
          WriteCmd(0x10);
          for(n=0;n<128;n++)
                   {
                   WriteDat(fill_Data);
                   }
         }
}
 
void OLED_CLS(void)
{
 OLED_Fill(0x00);
 
}

关于OLED的初始化函数如图所示

8.jpg


初始化里需要注意的主要就是这些指令,其中最关键的一些指令我通过一个表总结一下

30.010.jpg

最后还有显示字符的函数

void OLED_ShowStr(unsigned char x,unsigned char y,unsigned char ch[], unsigned char TextSize) //字符串显示函数
{
     unsigned char c=0,i=0,j=0;
     switch(TextSize)
	{  case 1:
	    {
		while(ch[j]!='\0')
	          {
	            c = ch[j] - 32;
		    if(x > 126)
		    {
			x = 0;
			y++;
		    }
		    OLED_SetPos(x,y);
		    for(i=0;i<6;i++)
		        WriteDat(F6x8[c][i]);
		    x += 6;
		    j++;
		  }
	    break;
	    }	
	   case 2:
	    {		
	      while(ch[j] != '\0')
		   {
			c = ch[j] - 32;
			if(x > 120)
			{
			    x = 0;
			    y++;
			}
			OLED_SetPos(x,y);
			for(i=0;i<8;i++)
			    WriteDat(F8X16[c*16+i]);
			OLED_SetPos(x,y+1);
			for(i=0;i<8;i++)
			    WriteDat(F8X16[c*16+i+8]);
			x += 8;
			j++;			
		    }
	   break;
		}
	}			
}

图中写的是两种大小的函数,分别是6*88*16两种大小,只需对应相应的ASCII字符,就能在显示屏上显示相应的英文,字符和数字。

OLED显示屏还可以显示中文字符和图片,具体函数有兴趣的同学可以研究研究,网上很容易能找到相应例程。

由于OLED没有字符库,所以需要用到取模软件手动取模,字符大小也要根据显示函数中字符大小来设置,取模时软件设置如图所示。

4.jpg

到此,“镜子里的屏幕”中所用到的最基本模块及程序就全部介绍完了,下一篇就是综合起来形成想要的效果。想知后事如何,请看下章分享(程序的整合与制作遇到的问题)。




共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]