STM8S驱动OLED12864

最新更新时间:2021-11-25来源: eefocus关键字:STM8S  驱动  OLED12864 手机看文章 扫描二维码
随时随地手机看文章


这种OLED的液晶屏似乎很受电子爱好者的欢迎,原因大概是:
①这种屏小巧玲珑,同样是128*64点阵的液晶屏,这种屏的体积比以前那种LCD12864小了四分之一,作为DIY手表的屏幕刚刚好。
②功耗低,由于OLED是有机发光材料制作成的,没有使用背光,所以功耗比使用LED作为背光的液晶屏,功耗要低很多。所以这块液晶屏适合用于手表之类的手持设备。
③可以选择的接口很多。接口和使用的液晶屏驱动芯片有关,大多数OLED12864使用的驱动芯片是SSD1306,这款驱动芯片提供给MCU的接口有5种,如下图。本文使用I2C接口来驱动OLED,主要是因为I2C占用MCU的IO少,当然用SPI接口驱动OLED的也很多。

使用I2C接口时,D0脚作为I2C的SCLK时钟信号线,D1,D2作为SDA数据信号线。D/C#引脚做为地址设定引脚,该引脚接地,OLED器件地址为0x78,该引脚上拉,OLED器件地址为0x7A。

当使用I2C时,SCLK和SDA引脚要加上拉电阻,关于上拉电阻要注意:
①如果I2C的速度很低,使用10K的上拉电阻是可以的,这个低速大概是100KHz
②如果I2C的速度很高,要达到300KHz左右,这个上拉电阻的阻值应该为4.7K

在淘宝上买的OLED模块,有的直接焊接了10K的上拉电阻,这样对于需要I2C高速通信的用户来说,很不方便,不查看电路还以为是程序出了问题,很浪费时间。今天我就遇到了这个问题,查找了好长时间,手头上又没4.7K的电阻,只好又并了个10K的电阻。


上图是SSD1306的显存分布,y轴范围是0~7,分为8个页,x轴坐标是0~127.


上图是对OLED写入地址的设定.

SSD1306也有一些控制命令,详情请查看SSD1306的数据手册。

由于我的STM8L-DISCOVERY的芯片烧坏掉了,所以没办法再继续用STM8L来写程序了。去淘宝买了块STM8S103F3的最小系统板,使用STM8L-DISCOVERY上的SWIM进行仿真调试。


第一次遇到,超过2000字不能发表的情况,大概是程序太长了。我把程序上传到GitHub了,刚刚摸索着使用这个国外的网站进行代码托管,由于是全英文的网站,还不是很会用。


/*硬件连接*/

// PB4--SCL   PB5--SDA

/****************************************************************************************

*开发环境:IAR for stm8 v6.5.3

*硬件平台:STM8S103F3

*功能说明:通过硬件I2C等待的方法,

*作    者:茗风

****************************************************************************************/

#include"iostm8s103f3.h"

#include"stdbool.h"

#include"stdint.h"


/******************************************************************************************************

* 名 称: uint8_t I2C_ReadOneByteDataFromSlave(uint8_t address)

* 功 能:从I2C从设备中读取一字节的数据

* 入口参数:address:读取数据的寄存器地址

* 出口参数:返回一个从I2C从设备指定地址读到的数据

* 说 明:

* 范 例:无

******************************************************************************************************/

uint8_t I2C_ReadOneByteDataFromSlave(uint8_t slave_address,uint8_t address)

{

  volatile uint8_t t;

  //----------I2C起始信号--------------

  I2C_CR2_START=1;//产生一个起始条件

  while(!(I2C_SR1_SB==1));//读SR1寄存器,清除SB标志位

//  _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  

  //-------发送写I2C从器件地址---------

  I2C_DR=slave_address;//发送从设备地址

  while(!(I2C_SR1_ADDR==1));//读SR1寄存器,清除ADDR标志位

// _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  if(I2C_SR3_TRA==0)return 1;//读SR3寄存器,清除ADDR标志位

  //  0: Data bytes received

  //  1: Data bytes transmitted

  

  //-----写I2C从器件寄存器地址--------

  I2C_DR=address;

  while(!(I2C_SR1_BTF==1));//等待地址发送完成

//  _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  

  //--------I2C重复起始信号-----------

  I2C_CR2_START=1;//重复产生一个起始条件

  while(!(I2C_SR1_SB==1));//读SR1寄存器,清除SB标志位

//  _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  

  //-------发送读I2C从器件地址---------

  I2C_DR=0xD1;//发送从设备地址

  while(!(I2C_SR1_ADDR==1));//读SR1寄存器,清除ADDR标志位

//  _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  if(I2C_SR3_TRA==1)return 1;//读SR3寄存器,清除ADDR标志位

  

  //-------------停止信号-------------

  I2C_CR2_ACK=0;//ACK位控制着ACK信号,此位为0可以产生一个NOACK信号

  I2C_CR2_STOP=1;

  

  //-------------等待接收到数据-------------

  while(!(I2C_SR1_RXNE==1));//等待地址发送完成

  

  //-------------读取数据-------------

  t=I2C_DR;

  

  return t;

}

/******************************************************************************************************

* 名 称:void I2C_WriteOneByteDataToSlave(uint8_t address,uint8_t dat)

* 功 能:写入一字节的数据到I2C设备中

* 入口参数:address:写入的数据存储地址    dat:待写入的数据

* 出口参数:无

* 说 明: 通过MSTM8L硬件写入I2C设备一个字节的数据

* 范 例:无

******************************************************************************************************/

uint8_t I2C_WriteOneByteDataToSlave(uint8_t slave_address,uint8_t address,uint8_t dat)

{

  volatile uint8_t t;

  I2C_CR2_ACK=1;

  //----------I2C起始信号--------------

  I2C_CR2_START=1;//产生一个起始条件

  while(!(I2C_SR1_SB==1));

// _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  I2C_DR=slave_address;

  

  //--------写I2C从器件地址-----------

  while(!(I2C_SR1_ADDR==1));

//  _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  if(I2C_SR3_TRA==0)return 1;//读SR3寄存器,清除ADDR标志位

  

  //-----写I2C从器件寄存器地址--------

  while(!(I2C_SR1_TXE==1));

  I2C_DR=address;

  

  //-------写I2C数据到寄存器中--------

  while(!(I2C_SR1_TXE==1));

  I2C_DR=dat;

  while(!(I2C_SR1_TXE==1));

  while(!(I2C_SR1_BTF==1));

// _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  

  //-------------停止信号-------------

  I2C_CR2_STOP=1;

  return 0;

}

/******************************************************************************************************

* 功    能:从I2C从设备读取多个字节数据

* 入口函数:

* 出口函数:

* 说    明:

* 范    例:

* 日    期:

******************************************************************************************************/

uint8_t I2C_ReadMultiBytesFromSlave(uint8_t slave_address,uint8_t address,uint8_t *rxbuf,uint8_t len)

{

  volatile uint8_t i=0;

  

  if(len==0)return 1;//如果写入字节长度为0退出

  

  I2C_CR2_ACK=1;

  //----------I2C起始信号--------------

  I2C_CR2_START=1;//产生一个起始条件

  while(!(I2C_SR1_SB==1));//读SR1寄存器,清除SB标志位

  

  //-------发送写I2C从器件地址---------

  I2C_DR=slave_address;//发送从设备地址

  while(!(I2C_SR1_ADDR==1));//读SR1寄存器,清除ADDR标志位

  if(I2C_SR3_TRA==0)return 1;//读SR3寄存器,清除ADDR标志位

  //  0: Data bytes received

  //  1: Data bytes transmitted

  

  //-----写I2C从器件寄存器地址--------

  I2C_DR=address;

  while(!(I2C_SR1_BTF==1));//等待地址发送完成

  

  //--------I2C重复起始信号-----------

  I2C_CR2_START=1;//重复产生一个起始条件

  while(!(I2C_SR1_SB==1));//读SR1寄存器,清除SB标志位

  

  //-------发送读I2C从器件地址---------

  I2C_DR=0xD1;//发送从设备地址

  while(!(I2C_SR1_ADDR==1));//读SR1寄存器,清除ADDR标志位

  if(I2C_SR3_TRA==1)return 1;//读SR3寄存器,清除ADDR标志位

  //-------------读取数据-------------

  if(len>1)

  {

      for( i=len;i>1;i-- )

      {

        while(!(I2C_SR1_RXNE==1));//等待I2C_DR接收到数

        *rxbuf++ = I2C_DR;  

      }

  }


  //-------------停止信号-------------

  I2C_CR2_ACK=0;//ACK位控制着ACK信号,此位为0可以产生一个NOACK信号

  I2C_CR2_STOP=1;

  

  while(!(I2C_SR1_RXNE==1));//等待I2C_DR接收到数

  *rxbuf++ = I2C_DR;

  

  return 0;

}

/******************************************************************************************************

* 名     称:IIC_init()

* 功     能:初始化I2C,系统主频位8MHz,I2C通信速度333KHz

* 入口 参数:无

* 出口 参数:无

* 说     明:PB4--SCL   PB5--SDA

* 范     例:无

******************************************************************************************************/

void I2C_Init(void)

{

  //----打开IIC外设时钟----

  I2C_CR1_PE=0;

  I2C_CR2_ACK=1;

  

  //----I2C输入时钟频率选择----

  I2C_FREQR_FREQ=0x08;//8MHz

  /*  The allowed range is between 1 MHz and 16 MHz

  000000: not allowed

  000001: 1 MHz

  000010: 2 MHz

  ...

  010000: 16 MHz                                 */

  

  //----配置时钟控制寄存器----

  I2C_CCRH=0;

  I2C_CCRH_F_S=1; //Fast mode I2C

  I2C_CCRH_DUTY=0;

/* If DUTY = 0:

Period(I2C) = 3* CCR * tMASTER

thigh = CCR * tMASTER

tlow = 2 * CCR * tMASTER*/

  I2C_CCRL=7;    //SCL高电平时间配置

  //I2C的SCK时钟设置为400KHz,则SCK周期为2.5us   2.5us/0.125/3=7   

  //因为I2C_FREQR_FREQ=0x08,即I2C输入时钟频率为8M,周期为0.125us  

  //CCR=7时,SCK的低电平时间为2*tlow=2*7*0.125us=1.75us,SCk高电平时间为thigh=7*0.125us=0.875us

  //所以CCR=7时,SCK输出频率为380KHz

  

  //----配置上升时间寄存器----

  I2C_TRISER_TRISE=5;//in standard mode, the maximum allowed SCL rise time is 1000 ns.

  //1 us / 0.125 us = 8

  //+1

  I2C_CR1_PE=1;//

}

#define  Write_CMD_TO_OLED12864(byte)  I2C_WriteOneByteDataToSlave(0x78,0x00,byte)

#define  Write_DAT_TO_OLED12864(byte)  I2C_WriteOneByteDataToSlave(0x78,0x40,byte)


/************************************6*8的点阵************************************/

const uint8_t ASCII_6X8[92][6] =           //水平寻址

{

    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // sp

    { 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 },   // !

    { 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 },   // "

    { 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 },   // #

    { 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 },   // $

    { 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 },   // %

    { 0x00, 0x36, 0x49, 0x55, 0x22, 0x50 },   // &

    { 0x00, 0x00, 0x05, 0x03, 0x00, 0x00 },   // '

    { 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 },   // (

    { 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 },   // )

    { 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 },   // *

    { 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 },   // +

    { 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 },   // ,

    { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08 },   // -

    { 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 },   // .

    { 0x00, 0x20, 0x10, 0x08, 0x04, 0x02 },   // /

    { 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E },   // 0

    { 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 },   // 1

    { 0x00, 0x42, 0x61, 0x51, 0x49, 0x46 },   // 2

    { 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 },   // 3

    { 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 },   // 4

    { 0x00, 0x27, 0x45, 0x45, 0x45, 0x39 },   // 5

    { 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 },   // 6

    { 0x00, 0x01, 0x71, 0x09, 0x05, 0x03 },   // 7

    { 0x00, 0x36, 0x49, 0x49, 0x49, 0x36 },   // 8

    { 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E },   // 9

    { 0x00, 0x00, 0x36, 0x36, 0x00, 0x00 },   // :

[1] [2] [3]
关键字:STM8S  驱动  OLED12864 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic555607.html

上一篇:stm8的18b20温度显示程序
下一篇:STM8单片机无线315&433脉宽自适应_通用解码程序

推荐阅读

STM8S单片机红外接收解码程序 带1602显示
这几天在网上找了很多关于红外接收解码的程序,但都不是很理想。一般都是用延时来作为0和1的数据,或者注释不是很详细的,所以自己鼓捣了一个。本程序是采用外部中断加定时器1来实现红外解码,STM8S单片机ABCD口都可作为外部中断,使用的遥控器为市面上大多数的。需要的朋友们可以作为参考。制作出来的实物图如下:效果图单片机源程序如下:/***************可识别用户码 解码成功后显示在1602并LED闪烁一次*****************/#include "iostm8s208mb.h"//主控芯片的头文件#define u8  unsigned char#define u16
发表于 2021-11-25
<font color='red'>STM8S</font>单片机红外接收解码程序 带1602显示
stm8 stm8s stm8af 485接口 modbus协议代码
本人使用stm8af62a6,stm8s和stm8af大多数是互通的,只用一个库函数62a6只能使用uart3!485接口是硬件,不需要管,任何硬件接线都可以实现代码见附件,已实现通信主函数代码,主要为初始化函数,以及modbus帧接收处理函数,帧接收处理按自己的需求自行修改,本例的处理函数为接收数据再多输出一点数据单片机源程序如下:/******************************************************************mian.c文件部分******************************************************************/void
发表于 2021-11-12
STM8S学习笔记之三(STM8 SysClk)
STM8S系统时钟设置,对于单片机来说是非常重要的,不同的用处必须应用不同的时钟。。举个例子,做AVR时在高稳定的串口通讯时用的时钟一般是3.6864M,主要是这个算波特率精确。。STM8S同样重要。STM8S时钟源:●1-24MHz高速外部晶体振荡器(HSE)●最大24MHz高速外部时钟信号(HSE user-ext)●16MHz高速内部RC振荡器(HSI)●128KHz低速内部RC(LSI)各个时钟源可单独打开或关闭,从而优化功耗。对于我这么懒得人一般都是用的内部或者外部晶振。。这个芯片时钟方面很大的一个亮点就是时钟可以自由分频。在降低功耗方面,如果有特殊需求的时候还是考虑STM8L系列或者430的吧,不得不承认术业有专攻
发表于 2021-11-10
STM8S定时器工作
TIM4是一个8位通用定时器,TIM4工作时,其计数器从0开始向上计数,计数到TIM4_ARR寄存器中设置的值时,计数器从新从0开始计数,同时产生一个计数器溢出事件。程序实例void main(void){  InitLED();  InitTIM4();  asm("ris");  TIM4_CR1 |= 0X01;   while(1){}}InitTIM4();为 TIM4 初始化函数,起作用是设置 TIM4 的相关寄存器,使 TIM4 每隔一段时间产生一次溢出中断。其函数内部如下:void InitTIM4(void){  TIM4_PSCR =
发表于 2021-10-20
STM8S定时器的使用 - stm8s定时器tim4使用方法解析
  stm8s定时器TIm4概述  该定时器由的8可位自动重载的向上计数器所组成,它可以用来作为时基发生器,具有溢出中断功能。  TIM6同时钟信号控制器用于定时器同步和级联。  STM8通用定时器TIM4的主要功能  TIM4功能包括:  1、8位向上计数的自动重载计数器;  2、3位可编程的预分配器(可在运行中修改),提供1,2,4,8,16,32,64和128这8种分频比例。  3、中断产生  –在计数器更新时:计数器溢出  STM8通用定时器TIM4功能概述    (TIM4框图 )  中断  通用定时器包括2个中断源:  更新中断(溢出,计数器初始化);  触发信号输入(仅TIM6可用)  STM8S定时器的使用  环境
发表于 2021-10-20
<font color='red'>STM8S</font>定时器的使用 - <font color='red'>stm8s</font>定时器tim4使用方法解析
业内消息称OLED显示驱动IC或在2022年吃紧
业内消息人士称,OLED显示驱动IC (DDI) 供应可能在2022年吃紧,芯片短缺可能会影响智能手机的出货量。据digitimes报道,消息人士指出,联咏、奇景光电、敦泰、瑞鼎等中国台湾地区的DDI供应商都在加强OLED DDI的开发和生产,希望在2022年提高此类芯片的出货率,届时OLED屏幕有望在新智能手机中大量采用。Digitimes Research预计2022年全球手机OLED面板出货量将达到7.13亿片,但OLED DDI出货量仅为6.50-6.6亿片,明显供不应求。另外,消息人士称,2022年手机用OLED DDI的实际短缺情况将取决于终端手机的销售结果,但随着OLED智能手机的渗透率在未来几年稳步上升,预计长期
发表于 2021-11-26
小广播
何立民专栏 单片机及嵌入式宝典

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

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2021 EEWORLD.com.cn, Inc. All rights reserved