基于STC15W408AS单片机IIC驱动OLED

控制/MCU

1882人已加入

描述

一、OLED显示屏

STC15W408AS单片机并没有提供IIC总线的接口,但是我们可以通过模拟IIC的方式实现。关于IIC总线的只是大家可以自行上网搜索。这里以驱动SSD1306芯片的0.96寸的128*64的OLED显示屏为例。

二、SSD1306芯片的IIC时序图

OLED

OLED

这里我们需要看清楚START信号和STOP信号。关于时间,芯片的数据手册也有说明。

OLED

IIC数据传输格式

OLED

这个是芯片的数据传输格式。

  1. The slave address is following the start condition for recognition use. For the SSD1306, the slave address is either “b0111100” or “b0111101” by changing the SA0 to LOW or HIGH (D/C pin acts as SA0).

手册中的这句话和上图右下角的,也说明了芯片的器件地址是0x78或者0x79。至于我们用的OLED液晶是哪一个,需要我们用这两个地址测试,我没找到哪个手册有说明,具体是哪一个。

关于芯片的寄存器,手册上面有很多,这里不做说明,自己查阅手册即可。

三、测试程序

1.IIC.h文件

#ifndef __IIC_H_
#define __IIC_H_
#define u16 unsigned int 
#define u8  unsigned char


void IIC_Start();
void IIC_Stop();
void IIC_Write_Byte(u8 byte);
void IIC_Wait_Ack();
void IIC_Write_Command(u8 cmd);
void IIC_Write_Data(u8 dat);
#endif

2.IIC.c文件

#include "stc15.h"
#include "iic.h"
#define IIC_SCL   P10   // 时钟
#define IIC_SDA   P11   // 数据
// IIC 开始信号
void IIC_Start()
{
  IIC_SCL = 1 ;
  IIC_SDA = 1;
  IIC_SDA = 0;
  IIC_SCL = 0;
}
// IIC 停止信号
void IIC_Stop()
{
  IIC_SCL = 1 ;
//  IIC_SCL = 0;
  IIC_SDA = 0;
  IIC_SDA = 1; 
}
// IIC 应答信号
void IIC_Wait_Ack()
{
  IIC_SCL = 1 ;
  IIC_SCL = 0;
}
// IIC 写一字节数据
void IIC_Write_Byte(u8 IIC_Byte)
{
  u8 i;
  u8 m,da;
  da = IIC_Byte;
  IIC_SCL = 0;
  for(i = 0;i < 8;i++)     
  {
    m = da;
    //  IIC_SCL = 0;
    m = m&0x80;
    if(m==0x80)
    {
      IIC_SDA = 1;
    }
    else IIC_SDA = 0;
      da = da< < 1;
    IIC_SCL = 1;
    IIC_SCL = 0;
  }
}

3.OLED.h文件

#ifndef __OLED_H_
#define __OLED_H_
#define u16 unsigned int 
#define u8  unsigned char


#define OLED_CMD  0  // 写命令
#define OLED_DATA 1  // 写数据
#define OLED_MODE 0 // 显示模式
//OLED模式设置
//0:4线串行模式
//1:并行8080模式
#define OLED_Address 0x78
#define OLED_Cmd  0x00
#define OLED_Data 0x40
#define SIZE 16
#define XLevelL    0x02
#define XLevelH    0x10
#define Max_Column  128
#define Max_Row    64
#define  Brightness  0xFF 
#define X_WIDTH   128
#define Y_WIDTH   64    
//OLED控制用函数
void OLED_WR_Byte(u8 dat,u8 cmd);   
void OLED_Display_On(void);
void OLED_Display_Off(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 Char_Size);
void OLED_ShowNum(u8 x,u8 y,u16 num,u8 len,u8 size2);
void OLED_ShowString(u8 x,u8 y, u8 *p,u8 Char_Size);    
void OLED_Set_Pos(u8 x, u8 y);
void OLED_ShowCHinese(u8 x,u8 y,u8 no);
void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[]);
void fill_picture(u8 fill_Data);
void Picture();
#endif

4.OLED.c文件

#include "oled.h"
#include "iic.h"
#include "oledfont.h"     
// IIC 写命令
void IIC_Write_Command(u8 IIC_Command)
{
  IIC_Start();
  IIC_Write_Byte(OLED_Address);           
  IIC_Wait_Ack();   
  IIC_Write_Byte(OLED_Cmd);       
  IIC_Wait_Ack();   
  IIC_Write_Byte(IIC_Command);  
  IIC_Wait_Ack();   
  IIC_Stop();
}
// IIC 写数据
void IIC_Write_Date(u8 IIC_Data)
{
  IIC_Start();
  IIC_Write_Byte(OLED_Address);     
  IIC_Wait_Ack();   
  IIC_Write_Byte(OLED_Data);   
  IIC_Wait_Ack();   
  IIC_Write_Byte(IIC_Data);
  IIC_Wait_Ack();   
  IIC_Stop();
}
// 往OLED写一字节数据
void OLED_WR_Byte(u8 dat,u8 cmd)
{
  if(cmd)
  {
    IIC_Write_Date(dat);
  }
  else {
   IIC_Write_Command(dat);   
  }
}
/********************************************
// fill_Picture
********************************************/
void fill_picture(u8 fill_Data)
{
  u8 m,n;
  for(m=0;m< 8;m++)
  {
    OLED_WR_Byte(0xb0+m,0);    //page0-page1
    OLED_WR_Byte(0x00,0);    //low column start address
    OLED_WR_Byte(0x10,0);    //high column start address
    for(n=0;n< 128;n++)
    {
      OLED_WR_Byte(fill_Data,1);
    }
  }
}
//坐标设置
void OLED_Set_Pos(u8 x, u8 y)  
{    
  OLED_WR_Byte(0xb0+y,OLED_CMD);
  OLED_WR_Byte(((x&0xf0) > >4)|0x10,OLED_CMD);
  OLED_WR_Byte((x&0x0f),OLED_CMD);  
}        
//开启OLED显示    
void OLED_Display_On(void)
{
  OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
  OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
  OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}
//关闭OLED显示     
void OLED_Display_Off(void)
{
  OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
  OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
  OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}               
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!    
void OLED_Clear(void)   
{   
  u8 i,n;         
  for(i=0;i< 8;i++)   
  {   
    OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
    OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
    OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
    for(n=0;n< 128;n++)OLED_WR_Byte(0,OLED_DATA);  
  } //更新显示
}
void OLED_On(void)   
{   
  u8 i,n;         
  for(i=0;i< 8;i++)   
  {   
    OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
    OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
    OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
    for(n=0;n< 128;n++)OLED_WR_Byte(1,OLED_DATA);  
  } //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示         
//size:选择字体 16/12 
void 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)
  {
    OLED_Set_Pos(x,y);   
    for(i=0;i< 8;i++)
    OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
    OLED_Set_Pos(x,y+1);
    for(i=0;i< 8;i++)
    OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
  }
  else {   
    OLED_Set_Pos(x,y);
    for(i=0;i< 6;i++)
    OLED_WR_Byte(F6x8[c][i],OLED_DATA);
  }
}
//m^n函数
u16 oled_pow(u8 m,u8 n)
{
  u16 result=1;    
  while(n--)result*=m;     
  return result;
}           
//显示2个数字
//x,y :起点坐标   
//len :数字的位数
//size:字体大小
//mode:模式  0,填充模式;1,叠加模式
//num:数值(0~4294967295);         
void OLED_ShowNum(u8 x,u8 y,u16 num,u8 len,u8 size2)
{            
  u8 t,temp;
  u8 enshow=0;                
  for(t=0;t< len;t++)
  {
    temp=(num/oled_pow(10,len-t-1))%10;
    if(enshow==0&&t< (len-1))
    {
      if(temp==0)
      {
        OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
        continue;
      }else enshow=1;  


    }
     OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);  
  }
}  
//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
{
  u8 j=0;
  while (chr[j]!='\\0')
  {     
    OLED_ShowChar(x,y,chr[j],Char_Size);
    x+=8;
    if(x >120){x=0;y+=2;}
    j++;
  }
}
//显示汉字
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{                 
  u8 t;
  OLED_Set_Pos(x,y);   
  for(t=0;t< 16;t++)
  {
    OLED_WR_Byte(Hzk[no][t],OLED_DATA);
  }   
  OLED_Set_Pos(x,y+1);   
  for(t=0;t< 16;t++)
  {   
    OLED_WR_Byte(Hzk[no][t+16],OLED_DATA);
  }           
}
/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[])
{    
  u16 j=0;
  u8 x,y;
  if(y1%8==0) y=y1/8;       
  else y=y1/8+1;
  for(y=y0;y< y1;y++)
  {
    OLED_Set_Pos(x0,y);
    for(x=x0;x< x1;x++)
    {       
      OLED_WR_Byte(BMP[j++],OLED_DATA);         
    }
  }
}  
//初始化SSD1306              
void OLED_Init(void)
{    
  OLED_WR_Byte(0xAE,OLED_CMD);//Set Display ON/OFF 关闭显示
  OLED_WR_Byte(0x40,OLED_CMD);//Set Display Start Line
  OLED_WR_Byte(0xB0,OLED_CMD);//Set Page Start Address for Page Addressing Mode
  OLED_WR_Byte(0xC8,OLED_CMD);//重映射模式
  OLED_WR_Byte(0x81,OLED_CMD);//设置对比度
  OLED_WR_Byte(0xFF,OLED_CMD);
  OLED_WR_Byte(0xA1,OLED_CMD);//垂直寻址方式
  OLED_WR_Byte(0xA6,OLED_CMD);//正常显示
  OLED_WR_Byte(0xA8,OLED_CMD);//设置驱动路数
  OLED_WR_Byte(0x1F,OLED_CMD);
  OLED_WR_Byte(0xD3,OLED_CMD);//Set Display Offset 设置垂直移位0d~63d
  OLED_WR_Byte(0x00,OLED_CMD);
  OLED_WR_Byte(0xD5,OLED_CMD);//Set Display Clock Divide Ratio/ Oscillator Frequency
  OLED_WR_Byte(0xF0,OLED_CMD);
  OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-charge Period
  OLED_WR_Byte(0x22,OLED_CMD);//Set Page Address
  OLED_WR_Byte(0xDA,OLED_CMD);//设置COM引脚硬件配置
  OLED_WR_Byte(0x02,OLED_CMD);
  OLED_WR_Byte(0xDB,OLED_CMD);//调整VCOMH调节器输出
  OLED_WR_Byte(0x49,OLED_CMD);
  OLED_WR_Byte(0x8D,OLED_CMD);
  OLED_WR_Byte(0x14,OLED_CMD);
  OLED_WR_Byte(0xAF,OLED_CMD);//Set Display ON/OFF 打开显示
  OLED_Clear();
}

关于字体文件和图片数据文件这里不贴代码了。关于其他的显示代码也不写了,网上很多。

5.main.c文件

#include "stc15.h"
#include "delay.h"
#include "oled.h"
#include "bmp.h"
int main(void)
{  
  OLED_Init();//初始化OLED  
  OLED_Clear() ;   
  while(1)  
  {     
    OLED_ShowCHinese(0,0,0);//小
    OLED_ShowCHinese(18,0,1);//猿
    OLED_ShowCHinese(36,0,2);//猪 
    OLED_ShowCHinese(54,0,3);//哥  
    }      
}
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分