NO.10 1.3寸OLED显示屏IIC通信(12864驱动芯片)

发布者:电子设计艺术家最新更新时间:2022-12-21 来源: elecfans关键字:显示屏  IIC通信 手机看文章 扫描二维码
随时随地手机看文章

  对于单片机来说,有一个良好的人机交互界面是很重要的。那么我们常用的单片机显示设备有什么呢?OLED屏是一个不错选择。

  

  OLED能显示我们的相对应的信息,使得我们的电子设计顿时高大上许多。

  OLED是啥呢?OLED跟LED差不多,简单点说,就是一个个小小的LED组合起来,控制每一个小小的LED灯像素的亮灭来进行显示,这样就可以显示任意字符了。

  对于OLED来说,单位面积内像素点的个数直接决定了我们显示屏的分辨率。像我在某宝购买的OLED显示屏,是1.3寸内有128*64个像素点。

  显然我们是不可能搞这么多的GPIO口来控制这个OLED的,那么我们该如何控制呢?

  前人早就为我们想好的解决措施,人家造了专门控制这种OLED的芯片方便我们使用,我们只需要按照芯片所需要的通信协议跟芯片通信就可以操作这个OLED了。

  那么我们应该用什么通信协议呢?这个芯片支持IIC和SPI两种通信方式,这里我们主要使用讲解IIC。

   I2C 总线是一种串行数据总线,只有二根信号线,一根是双向的数据线SDA,另一根是时钟线SCL,两条线可以挂多个设备。 IIC设备(绝大多数)里有个固化的地址,只有在两条线上传输的值等于IIC设备的固化地址时,其才会作出响应。通常我们为了方便把IIC设备分为主设备和从设备,基本上谁控制时钟线(即控制SCL的电平高低变换)谁就是主设备。

  我们操作OLED显示屏就是属于最简单的一种IIC应用。我们只需要向OLED发送数据,而不需要接收OLED发送的数据。

  IIC的具体通信协议我就不详细说了,主要分为起始信号,应答信号,结束信号,同时向设备发送数据或者接收数据。

  对于我们的MSP432中,其实是自带了IIC的库,但是为了我们方便理解(才不是我老是发送不了数据呢),我们使用软件模拟IIC。

  那什么又是软件模拟IIC呢?就是拿GPIO口当做SCL和SDA,自己来控制传输线的高低电平!

  我们万能的某宝卖家写了利用51和STM32操作OLED例程,我们只需要对其修改下就可以运用到我们的MSP432中。

  下面我列出所有核心函数:

//起始信号

void I2C_Start(void)

{

    GPIO_write(CONFIG_GPIO_SDA,1);

    GPIO_write(CONFIG_GPIO_SCL,1);

    GPIO_write(CONFIG_GPIO_SDA,0);

    GPIO_write(CONFIG_GPIO_SCL,0);

}


//结束信号

void I2C_Stop(void)

{

    GPIO_write(CONFIG_GPIO_SDA,0);

    GPIO_write(CONFIG_GPIO_SCL,1);

    GPIO_write(CONFIG_GPIO_SDA,0);

}


//等待信号响应

void I2C_WaitAck(void) //测数据信号的电平

{

    GPIO_write(CONFIG_GPIO_SDA,1);

    GPIO_write(CONFIG_GPIO_SCL,1);

    GPIO_write(CONFIG_GPIO_SCL,0);

}


//写入一个字节

void Send_Byte(uint8_t dat)

{

  uint8_t i;

  for(i=0;i<8;i++)

  {

    GPIO_write(CONFIG_GPIO_SCL,0);//将时钟信号设置为低电平

    if(dat&0x80)//将dat的8位从最高位依次写入

    {

        GPIO_write(CONFIG_GPIO_SDA,1);

    }

    else

    {

        GPIO_write(CONFIG_GPIO_SDA,0);

    }

    GPIO_write(CONFIG_GPIO_SCL,1);

    GPIO_write(CONFIG_GPIO_SCL,0);

    dat<<=1;

  }

}


//发送一个字节

//向SSD1306写入一个字节。

//mode:数据/命令标志 0,表示命令;1,表示数据;

void OLED_WR_Byte(uint8_t dat,uint8_t 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();

}


//坐标设置

void OLED_Set_Pos(uint8_t x, uint8_t 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)

{

  uint8_t 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);

  } //更新显示

}


//在指定位置显示一个字符,包括部分字符

//x:0~127

//y:0~63

//sizey:选择字体 6x8  8x16

void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t sizey)

{

  uint8_t c=0,sizex=sizey/2;

  uint16_t i=0,size1;

  if(sizey==8)size1=6;

  else size1=(sizey/8+((sizey%8)?1:0))*(sizey/2);

  c=chr-' ';//得到偏移后的值

  OLED_Set_Pos(x,y);

  for(i=0;i  {

    if(i%sizex==0&&sizey!=8) OLED_Set_Pos(x,y++);

    if(sizey==8) OLED_WR_Byte(asc2_0806[c][i],OLED_DATA);//6X8字号

    else if(sizey==16) OLED_WR_Byte(asc2_1608[c][i],OLED_DATA);//8x16字号

    //      else if(sizey==xx) OLED_WR_Byte(asc2_xxxx[c][i],OLED_DATA);//用户添加字号

    else return;

  }

}

//m^n函数

uint32_t oled_pow(uint8_t m,uint8_t n)

{

  uint32_t result=1;

  while(n--)result*=m;

  return result;

}

//显示数字

//x,y :起点坐标

//num:要显示的数字

//len :数字的位数

//sizey:字体大小

void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t sizey)

{

  uint8_t t,temp,m=0;

  uint8_t enshow=0;

  if(sizey==8)m=2;

  for(t=0;t  {

    temp=(num/oled_pow(10,len-t-1))%10;

    if(enshow==0&&t<(len-1))

    {

      if(temp==0)

      {

        OLED_ShowChar(x+(sizey/2+m)*t,y,' ',sizey);

        continue;

      }else enshow=1;

    }

    OLED_ShowChar(x+(sizey/2+m)*t,y,temp+'0',sizey);

  }

}

//显示一个字符号串

void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t sizey)

{

  uint8_t j=0;

  while (chr[j]!='')

  {

    OLED_ShowChar(x,y,chr[j++],sizey);

    if(sizey==8)x+=6;

    else x+=sizey/2;

  }

}

//显示汉字


void OLED_ShowChinese(uint8_t x,uint8_t y,uint8_t no,uint8_t sizey)

{

  uint16_t i,size1=(sizey/8+((sizey%8)?1:0))*sizey;

  for(i=0;i  {

    if(i%sizey==0) OLED_Set_Pos(x,y++);

    if(sizey==16) OLED_WR_Byte(Hzk[no][i],OLED_DATA);//16x16字号

    //      else if(sizey==xx) OLED_WR_Byte(xxx[c][i],OLED_DATA);//用户添加字号

    else return;

  }

}


//显示图片

//x,y显示坐标

//sizex,sizey,图片长宽

//BMP:要显示的图片

void OLED_DrawBMP(uint8_t x,uint8_t y,uint8_t sizex, uint8_t sizey,uint8_t BMP[])

{

  uint16_t j=0;

  uint8_t i,m;

  sizey=sizey/8+((sizey%8)?1:0);

  for(i=0;i  {

    OLED_Set_Pos(x,i+y);

    for(m=0;m    {

      OLED_WR_Byte(BMP[j++],OLED_DATA);

    }

  }

}



//初始化SSD1306

void OLED_Init(void)

{

  sleep(1);

  OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel

  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  Set Mapping RAM Display Start Line (0x00~0x3F)

  OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register

  OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness

  OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常

  OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常

  OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display

  OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)

  OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty

  OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)

  OLED_WR_Byte(0x00,OLED_CMD);//-not offset

  OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency

  OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec

  OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period

  OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock

  OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration

  OLED_WR_Byte(0x12,OLED_CMD);

  OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh

  OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level

  OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)

  OLED_WR_Byte(0x02,OLED_CMD);//

  OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable

  OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable

  OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)

  OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)

  OLED_Clear();

  OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/

}


  程序有点长,大家直接复制就可以使用。


  那我们该如何调用呢?非常简单。比如我们显示某种字符,我们这样作为按键的回调函数,当我们按下按键就可以显示某种字符。


void gpioButtonFxn1(uint_least8_t index)

{

    /* Clear the GPIO interrupt and toggle an LED */

    GPIO_toggle(CONFIG_GPIO_LED_1);

    OLED_Clear();

    OLED_ShowString(10,4,"2020/05/28",8);

    OLED_ShowString(10,6,"DerekChen",8);

    sleep(1);

}


  哈!非常简单是不是。那么我们要显示中文呢?中文有点复杂,你需要先生成中文的字符点阵数据,然后就可以照样显示了!


关键字:显示屏  IIC通信 引用地址:NO.10 1.3寸OLED显示屏IIC通信(12864驱动芯片)

上一篇:NO.12 MSP432进行串口通信
下一篇:NO.9 矩阵键盘和MSP432实例——控制MSP开发板板载LED

推荐阅读最新更新时间:2024-11-14 10:48

为什么示波器带宽要≤1GHz,浅谈电源噪声测试
电源是整个系统的基石,哪怕板子上的线画的比神仙姐姐还好看,只要电源趴着不动,一切都白搭。如果扶一扶能起来还好,比如加点东西、换点东西后凑合着能用;扶不起来的话那就…… 好的电源应该是个什么样?两个字:干净!看着就让人莫名地放心。 那差的电源是个什么样呢?两个成语:毛毛躁躁、上蹿下跳!看着就让人不放心,透着一股子不靠谱的劲儿。 讲真的,颜值即是正义,在信号界也不例外! 当然长的啥样,光凭肉眼也看不出来,得用示波器看,这就涉及到怎么用示波器的问题。 常遇到客户咨询,问:“我的电源噪声好大!怎么会这样?怎么办?” ——额……我们先来聊聊好大是多大,听上去怪吓人的,咱能不能不用形容词描述,改用数据说话吧?电源是多少V的
[测试测量]
伊之密豪掷1亿在印度建厂
出海,成为了当下许多国产厂商的长期共识和迫切需求。 但是,随着华米 OV 在印度乃至欧洲遭遇的种种责难和封锁,将“出海”再次推向了风口浪尖。 对此,有企业认为,毕竟是个例,加上这些又都是大企业,对我们这些身处中位的企业而言,存在感并不强,矛头自然就不会瞄准我们。 但也有企业认为,毋庸置疑,出海是必要的,但现在出海未必是良机,尤其是被视为出海首选之地的印度、越南等,近来政策变化无常,时局并不明朗,所以还是需要再观望一下比较妥当。 比起国内尚未出海厂商的摇摆和观望,广东伊之密精密机械股份有限公司(下称“伊之密”)更喜欢押重注布局海外。 据伊之密负责海外市场业务的副总经理余妙宇透露,伊之密从成立第4年便跨
[机器人]
DRAM价Q1看跌5% 冲击厂商
进入淡季后,第1季DRAM价格将持续下跌,业者预期,单季跌幅可能超过5%,比第4季的跌价幅度稍大。这对于华亚科、南亚科等厂商的业绩,可能造成部分影响。业者强调,整体而言,今年的DRAM市况虽然可能不如去年,但还算乐观。 DRAM 业者指出,去年第4季DRAM价格跌幅约在5%以内,本季跌幅可能扩大,但还算健康的缓跌状态。PC DRAM与消费型DRAM因为处于淡季,价格可能跌幅较多,行动装置所使用的记忆体价格也应该会稍微下滑,较可能逆势上涨者,是需求相当强劲的伺服器用 DRAM,而且此类产品采用DDR 4规格的比例高,会拉升平均销售单价(ASP)。 不过在淡季之后,DRAM厂商寄望苹果下一代iPhone可
[手机便携]
TCL李东生:要大干一笔内定1亿台手机销量目标
    在互联网的风口上,究竟是坚守实业,还是另觅赚钱良方,李东生心中已有了答案。   4月8日下午,在深圳举行的TCL 2015春季新品发布会上,TCL集团董事长、CEO李东生宣布将对企业重新定位,并表示:“首先会坚守实业,但同时会顺应整个互联网发展的趋势,打造新的业务盈利。”   这时距离李东生提出TCL进行互联网战略转型整整一年。当天在接受《华夏时报》记者采访时,谈及TCL最出彩的智能手机业务,他放话称今年要在国内市场“大干一笔”。也许这只是其转型布局中的冰山一角。   转型一年后重新定位   在4月8日举行的新品发布会上,李东生对集团未来发展方向做了进一步明确,并宣布TCL新的企业定位是“全球化的智能产品制造
[手机便携]
苹果M1芯片升级了,服务于应用场景
在去年的苹果发布会上,其产品包含iMac全线切到使用苹果自主研发并设计的芯片M1系列,这个系列芯片也代表着苹果放弃x86架构,这一里程碑式性决定。关于其在架构选择方面的详细解读,可以参考之前的文章: 苹果发布M1芯片放弃X86架构 M1 Pro和Max都是去年M1的后续产品,M1是苹果的第一代Mac芯片,它开启了苹果用自己的内部设计取代基于x86芯片的征程。尽管M1速度很快,功耗表现也不错,但它仍然是一个更小的SoC——仍然为iPad Pro系列等设备供电,以及相应的较低的TDP(Thermal Design Power),自然还是输给功能更加强劲地芯片,关于技术细节,在之前的文章中均有提到,这里不再赘述。 那么我们已
[嵌入式]
苹果M<font color='red'>1</font>芯片升级了,服务于应用场景
美光宣布向人工智能创业公司投资1亿美元
据外媒报道,美光科技周三表示,计划向关注无人驾驶汽车、工厂自动化和其他新兴领域的人工智能创业公司投资最多1亿美元。 美光早在十几年前就启动了企业风投计划。不过美光首席业务官苏米特·萨达纳(Sumit Sadana)表示,到目前为止该公司的投资非常分散,并且大多接近该公司的核心业务,即芯片制造。 在旧金山举行的美光首次人工智能会议上,他表示,现有的风投业务回报率很好,但公司认为,通过扩大在人工智能领域的参与,最终有助于销售更多存储芯片,因为人工智能处理的是保存在存储芯片中的大量数据。美光此前的投资几乎从未被披露过。 萨达纳表示,新的资金将投资从事人工智能技术的硬件和软件创业公司。美光对投资无人驾驶汽车技术、增强现实和虚拟现实,以及工
[嵌入式]
vivo S1 Pro 5月9日上市 主打3200万升降光感自拍
新浪数码讯 5月7日下午消息,vivo曾于今年4月推出聚焦“自拍体验”的S系列,近日该系列的第二款产品S1 Pro也正式亮相并定于5月9日上市,整体配置和潮流外观相较首款产品S1有所提升,自拍体验也将升级。 vivo S1 Pro搭载3200万像素升降式前置摄像头,f/2.0大光圈,1/2.8英寸感光元件,vivo称它让手机成像更清晰、色彩更真实。优化升级的AI美颜搭配新上线的趣美颜、AI抠图、光影特效等功能,真正做到即拍即美,令每一张自拍都更加光彩动人。 这些功能搭配,让从零开始的自拍小白或高级玩家,都可从实现理想自拍体验。 vivo S1 Pro的后置摄像头组是4800万物理像素,800万像素超广角镜头(1
[手机便携]
英特尔Q1净利环比下降43%,宣布裁员1.2万人
北京时间4月20日凌晨消息,英特尔今天公布了2016财年第一季度财报。报告显示,英特尔第一季度营收为137亿美元,比去年同期的128亿美元增长7%;净利润为20.46亿美元,与去年同期的19.92亿美元相比增长3%。英特尔第一季度业绩超出华尔街分析师预期,但对第二季度营收的展望不及预期预期,推动其盘后股价下跌逾2%。同时,该公司还宣布将裁员1.2万人。 在截至4月2日的这一财季,英特尔的净利润为20.46亿美元,比去年同期的19.92亿美元增长3%,比上一季度的36亿美元下滑43%;每股收益为42美分,比去年同期的41美分增长2%,比上一季度的74美分下滑43%。不计入某些一次性项目(不按照美国通用会计准则),英特尔第一季度
[半导体设计/制造]
热门资源推荐
热门放大器推荐
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved