3204|2

606

帖子

20

TA的资源

一粒金砂(高级)

楼主
 

【基于GDF350的无线数字对讲机】3、玩转0.96寸OLED [复制链接]

本帖最后由 ketose 于 2018-10-2 21:58 编辑

1、0.96寸OLED介绍
        0.96’ OLED 显示模块, 分辨率为 128*64,采用SSD1306 驱动 IC,该芯片内部集成 DCDC 升压,仅需 3.3V 供电,即可正常工作。实际上就是由一个SSD1306控制器和一个128X64的有机发光二极管点阵组成。OLD模块具有和12864LCD相同的分辨率,但其在单位面积上具有更多的像素点。该模块的驱动芯片是SSD1306Z,它是一款专门用于驱动OLED点阵屏的COMS芯片,其包含128个段和64个公共端。为了能够通过外部控制器向其写入用于显示的数字信息,其对外提供了8个数据引脚和5个控制脚,并向用户提供了4种总线接口。文中所采用的OLED模块可实现SPI和IIC两种总线接口模式,默认为SPI模式。在SPI模式下,仅有数据引脚的低2位和控制引脚的CS#,D/C#和RES#与单片机进行接口。为了能让OLED具有丰富的显示效果和灵活简便的操作方式,SSD1306Z向用户提供了丰富的操作指令集,另外还向用户提供了128x64位的GDDRAM(Graphic Display Data RAM)。由于所采用的OLED不带字库,因此无论是显示图形还是显示汉字,均需通过取模软件进行编码,然后按SPI协议,将对应的编码按照所确定的地址模式写入对应的CDDRAM中。编码原理如图1所示。图1给出了16*8编码格式的字符‘A’,由于8行为一页,因此其占据2页的高度,而宽度则占据8列。图1中的每一个方格代表一位,若要显示则置1,反之置0。向GDDRAM当中送数据时,先通过指令确定操作所需的地址模式及存储器的地址,然后先写‘A’的第2页的编码,再写其第3页的编码,即可完成编码的写入操作。图1所对应的编码为0x00,0x00,0xe0,0x9c,0xf0,0x80,0x00,0x00,0x08,0x0f,0x08,0x00,0x00,0x0b,0xoe,0x08,编码时高位在下,低位在上。同理,可得对任意汉字的编码。

2、OLED模块及接口描述

3、驱动芯片SSD1306
      在SSD1306的内部有一个Graphic Display Data RAM(GDDRAM:图形显示数据内存),它有128×8字节,即128×64个Bits,每个Bits分别对应OLED的128×64个点,也就是每个像素点对应一个Bits。这些字节分别存储 PAGE0~PAGE7 中,每页存储128个字节,如图:

        这样刚好是 128*64 的点阵大小。因为每次写入都是按字节写入的,这就存在一个问题,如果我们使用只写方式操作模块,那么,每次要写 8 个点,这样,我们在画点的时候,就必须把要设置的点所在的字节的每个位都搞清楚当前的状态(0/1?),否则写入的数据就会覆盖掉之前的状态,结果就是有些不需要显示的点,显示出来了,或者该显示的没有显示了。这个问题在能读的模式下,我们可以先读出来要写入的那个字节,得到当前状况,在修改了要改写的位之后再写进 GRAM,这样就不会影响到之前的状况了。但是这样需要能读 GRAM,对于 4 线 SPI 模式或者 IIC 模式来说,模块是不支持读的,而且读->改->写的方式速度也比较慢。所以我这里推荐采用的办法是在单片机的内部建立一个 OLED 的 GRAM(需要 128*8 个字节),在每次修改的时候,只是修改单片机上的 GRAM(实际上就是 SRAM),在修改完了之后,一次性把单片机内部的 GRAM 写入到 OLED 的 GRAM。当然这个方法也有坏处,就是对于那些 SRAM 很小的单片机(比如 51 系列)就比较麻烦了,如果内存不够,那就推荐还是采用并口模式,这样可以节约内存。
4、实际效果
因为我的方案是做一个无线对讲,所以我用OLED来实时显示频普。先看效果

视频效果

不知道为什么论坛里嵌入的优酷视频打不开了,所以我把地址放出来。
http://v.youku.com/v_show/id_XMz ... m=a2hzp.8253869.0.0

5、最后还是要把OLED的驱动代码放出来
  1. /**
  2. ****************************************************************************************
  3. *
  4. * @file lcd_12864.c
  5. *
  6. * [url=home.php?mod=space&uid=159083]@brief[/url] lcd_12864 driver.
  7. *
  8. * Copyright (C) TChip 2014
  9. *
  10. * $Rev: 1.0 $
  11. *
  12. ****************************************************************************************
  13. */

  14. /**
  15. ****************************************************************************************
  16. * @addtogroup  SPI
  17. * @{
  18. ****************************************************************************************
  19. */

  20. /*
  21. * INCLUDE FILES
  22. ****************************************************************************************
  23. */
  24. #include "gd32f3x0.h"                   // Device header

  25. #include "systick.h"
  26. #include "oled.h"
  27. #include "oledfont.h"

  28. /*
  29. * MARCO VARIABLE DECLARATION
  30. ****************************************************************************************
  31. */
  32. #define TRANSFER_SIZE               (1)                /*! Transfer size */
  33. #define TRANSFER_BAUDRATE           (1000000U)           /*! Transfer baudrate - 500k */
  34. #define MASTER_TRANSFER_TIMEOUT     (5000U)             /*! Transfer timeout of master - 5s */
  35. /*
  36. * LOCAL VARIABLE DECLARATION
  37. ****************************************************************************************
  38. */
  39. //check spi status
  40. volatile uint8_t        oled_rx_flag = 0;
  41. volatile uint8_t        oled_tx_flag = 0;
  42. //双缓冲显存
  43. uint8_t OLED_GRAM1[9][128];
  44. uint8_t OLED_GRAM2[9][128];

  45. uint8_t* pGRAM_back;
  46. uint8_t* pGRAM_front;

  47. //Init the OLED
  48. //static uint8_t                 Init_buffer[] =
  49. //{
  50. //         0xAE ,//--turn off oled panel
  51. //         0x00 ,//---set low column address
  52. //         0x10 ,//---set high column address
  53. //         0x40 ,//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
  54. //         0x81 ,//--set contrast control register
  55. //         0xCF , // Set SEG Output Current Brightness
  56. //         0xA1 ,//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
  57. //         0xC8 ,//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
  58. //         0xA6 ,//--set normal display
  59. //         0xA8 ,//--set multiplex ratio(1 to 64)
  60. //         0x3f ,//--1/64 duty
  61. //         0xD3 ,//-set display offset        Shift Mapping RAM Counter (0x00~0x3F)
  62. //         0x00 ,//-not offset
  63. //         0xd5 ,//--set display clock divide ratio/oscillator frequency
  64. //         0x80 ,//--set divide ratio, Set Clock as 100 Frames/Sec
  65. //         0xD9 ,//--set pre-charge period
  66. //         0xF1 ,//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
  67. //         0xDA ,//--set com pins hardware configuration
  68. //         0x12 ,
  69. //         0xDB ,//--set vcomh
  70. //         0x40 ,//Set VCOM Deselect Level
  71. //         0x20 ,//-Set Page Addressing Mode (0x00/0x01/0x02)
  72. //         0x02 ,//
  73. //         0x8D ,//--set Charge Pump enable/disable
  74. //         0x14 ,//--set(0x10) disable
  75. //         0xA4 ,// Disable Entire Display On (0xa4/0xa5)
  76. //         0xA6 ,// Disable Inverse Display On (0xa6/a7)
  77. //         0xAF ,//--turn on oled panel
  78. //
  79. //         0xAF , /*display ON*/
  80. //};

  81. void ole_delay(uint32_t tick)
  82. {
  83.     while(tick-- > 0) __NOP();
  84. }

  85. /*
  86. * GLOBAL VARIABLE DECLARATION
  87. ****************************************************************************************
  88. */


  89. #if (GD32_OLED)

  90. /**
  91. ****************************************************************************************
  92. * @brief SPI RX CALLBACK FUNCTION.
  93. * @description
  94. *
  95. ****************************************************************************************
  96. */
  97. void oled_read_done(void)
  98. {
  99.     oled_rx_flag = 0;
  100. }

  101. /**
  102. ****************************************************************************************
  103. * @brief SPI TX CALLBACK FUNCTION.
  104. * @description
  105. *
  106. ****************************************************************************************
  107. */
  108. void oled_write_done(void)
  109. {
  110.     oled_tx_flag = 0;
  111. }

  112. /**
  113. ****************************************************************************************
  114. * @brief Configure the SPI GPIO and set RS  、 RST GPIO output,Init them.
  115. * @description
  116. *
  117. ****************************************************************************************
  118. */
  119. void oled_io_config(void)
  120. {
  121.     /* Configure SPI_MASTER pins: SCK and MOSI */
  122.     gpio_af_set(OLED_SCLK,GPIO_AF_0,OLED_SCLK_PIN|OLED_SDIN_PIN);
  123.     gpio_mode_set(OLED_SCLK,GPIO_MODE_AF,GPIO_PUPD_NONE,OLED_SCLK_PIN|OLED_SDIN_PIN);
  124.     gpio_output_options_set(GPIOB,GPIO_OTYPE_PP,GPIO_OSPEED_10MHZ,OLED_SCLK_PIN|OLED_SDIN_PIN);
  125.     //set the LCD_RS_PIN and LCD_RST_PIN an output
  126.     gpio_mode_set(OLED_DC,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,OLED_DC_PIN|OLED_RST_PIN|OLED_CS_PIN);
  127.     gpio_output_options_set(OLED_DC,GPIO_OTYPE_PP,GPIO_OSPEED_10MHZ,OLED_DC_PIN| OLED_RST_PIN|OLED_CS_PIN);

  128.     gpio_bit_reset(OLED_DC,OLED_DC_PIN);
  129.     gpio_bit_set(OLED_RST,OLED_RST_PIN);
  130. }


  131. void OLED_Set_Pos(unsigned char x, unsigned char y)
  132. {
  133.     OLED_WR_Byte(0xb0+y,OLED_CMD);
  134.     OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
  135.     OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD);
  136. }
  137. //开启OLED显示
  138. void OLED_Display_On(void)
  139. {
  140.     OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
  141.     OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
  142.     OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
  143. }
  144. //关闭OLED显示
  145. void OLED_Display_Off(void)
  146. {
  147.     OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
  148.     OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
  149.     OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
  150. }
  151. //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
  152. void OLED_Clear(void)
  153. {
  154.     uint8_t i,n;
  155.     for(i=0; i<8; i++)
  156.     {
  157.         OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
  158.         OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
  159.         OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址
  160.         for(n=0; n<128; n++)
  161.             OLED_WR_Byte(0,OLED_DATA);
  162.     } //更新显示
  163. }

  164. void OLED_WR_Byte(uint8_t dat,uint8_t cmd)
  165. {
  166.     if(cmd)
  167.         OLED_DC_Set();
  168.     else
  169.         OLED_DC_Clr();
  170.     OLED_CS_Clr();
  171.     //spi_write(QN_SPI1, buffer, 1, oled_write_done);
  172.     spi_i2s_data_transmit(SPI0,dat);
  173.     oled_write_done();
  174.     //delay_10us(1);
  175.     ole_delay(6);

  176.     OLED_CS_Set();
  177.     OLED_DC_Set();
  178. }


  179. void OLED_WR_Buffer(uint8_t* buffer,uint16_t bufLen,uint8_t cmd)
  180. {
  181.     if(cmd)
  182.         OLED_DC_Set();
  183.     else
  184.         OLED_DC_Clr();
  185.     OLED_CS_Clr();
  186.     //spi_write(QN_SPI1, buffer, 1, oled_write_done);
  187.     for(int i=0; i<bufLen; i++)
  188.     {
  189.         spi_i2s_data_transmit(SPI0,buffer[i]);
  190.         ole_delay(2);
  191.     }
  192.     oled_write_done();
  193.     //delay_10us(1);

  194.     OLED_CS_Set();
  195.     OLED_DC_Set();

  196. }

  197. void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr)
  198. {
  199.     unsigned char c=0,i=0;
  200.     c=chr-' ';//得到偏移后的值
  201.     if(x>7) {
  202.         x=0;
  203.         y=y+2;
  204.     }
  205.     for(i=0; i<6; i++)
  206.         pGRAM_back[128*x+y+i] = F6x8[c*6+i];
  207. }


  208. //显示一个字符号串
  209. void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr)
  210. {
  211.     unsigned char j=0;
  212.     while (chr[j]!='\0')
  213.     {
  214.         OLED_ShowChar(x,y,chr[j]);
  215.         y+=8;
  216.         if(y>120) {
  217.             x += 1;
  218.             y = 2;
  219.         }
  220.         j++;
  221.     }
  222. }

  223. /***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
  224. void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
  225. {
  226.     unsigned int j=0;
  227.     unsigned char x,y;

  228.     if(y1%8==0) y=y1/8;
  229.     else y=y1/8+1;
  230.     for(y=y0; y<y1; y++)
  231.     {
  232.         OLED_Set_Pos(x0,y);
  233.         for(x=x0; x<x1; x++)
  234.         {
  235.             OLED_WR_Byte(BMP[j++],OLED_DATA);
  236.         }
  237.     }
  238. }


  239. //更新显存到LCD
  240. void OLED_Refresh_Gram(void)
  241. {
  242.     uint8_t buf[128];
  243.     uint8_t i,n;
  244.     for(i=0; i<8; i++)
  245.     {
  246.         for(n=0; n<128; n++)
  247.         {
  248.             buf[n] = pGRAM_front[128*i +n];//OLED_GRAM[n][i];
  249.         }
  250.         OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
  251.         OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
  252.         OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址

  253.         OLED_WR_Buffer(buf,128,OLED_DATA);
  254.     }
  255. }


  256. void OLED_Refresh(void)
  257. {
  258.     /*为了提高效率,设置成水平地址模式*/

  259.     OLED_WR_Byte (0x20,OLED_CMD);            //设置内存地址模式:水平地址
  260.     OLED_WR_Byte (0x00,OLED_CMD);
  261.     OLED_WR_Byte (0x21,OLED_CMD);                //设置列开始和结束地址
  262.     OLED_WR_Byte (0x00,OLED_CMD);              //设置列的开始地址
  263.     OLED_WR_Byte (0x7F,OLED_CMD);              //设置列的结束地址

  264.     OLED_WR_Buffer(pGRAM_front,1024,OLED_DATA);
  265. }

  266. void SPI_config(void)
  267. {
  268.     spi_parameter_struct SPI_InitStructure;

  269.     /* SPI0 配置*/
  270.     SPI_InitStructure.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
  271.     SPI_InitStructure.device_mode = SPI_MASTER;
  272.     SPI_InitStructure.frame_size = SPI_FRAMESIZE_8BIT;
  273.     SPI_InitStructure.nss = SPI_NSS_SOFT;
  274.     SPI_InitStructure.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
  275.     SPI_InitStructure.prescale = SPI_PSC_2;
  276.     SPI_InitStructure.endian = SPI_ENDIAN_MSB;
  277.     spi_init(SPI0, &SPI_InitStructure);

  278.     spi_enable(SPI0);
  279. }

  280. //初始化SSD1306
  281. void OLED_Init(void)
  282. {
  283.     oled_io_config();
  284.     SPI_config();

  285.     OLED_RST_Set();
  286.     delay_1ms(10);
  287.     OLED_RST_Clr();
  288.     delay_1ms(10);
  289.     OLED_RST_Set();

  290.     pGRAM_back = (uint8_t*)OLED_GRAM1;
  291.     pGRAM_front = (uint8_t*)OLED_GRAM2;


  292.     OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
  293.     OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
  294.     OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
  295.     OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
  296.     OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
  297.     OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
  298.     OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
  299.     OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
  300.     OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
  301.     OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
  302.     OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
  303.     OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset        Shift Mapping RAM Counter (0x00~0x3F)
  304.     OLED_WR_Byte(0x00,OLED_CMD);//-not offset
  305.     OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
  306.     OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
  307.     OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
  308.     OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
  309.     OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
  310.     OLED_WR_Byte(0x12,OLED_CMD);
  311.     OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
  312.     OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
  313.     OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
  314.     OLED_WR_Byte(0x02,OLED_CMD);//
  315.     OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
  316.     OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
  317.     OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
  318.     OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
  319.     OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel

  320.     OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/
  321.     OLED_Clear();
  322.     OLED_Set_Pos(0,0);
  323. }

  324. #endif
  325. ///end


复制代码





此帖出自GD32 MCU论坛

最新回复

多谢分享!  详情 回复 发表于 2018-10-1 11:18
点赞 关注(2)
 

回复
举报

935

帖子

1

TA的资源

禁止发言

沙发
 
此帖出自GD32 MCU论坛
 
个人签名存储芯片/MCU/SRAM/PSRAM/DDR/FLASH/MRAM。web.www.sramsun.com  QQ3161422826 TEL:13751192923
 
 

回复

196

帖子

0

TA的资源

一粒金砂(中级)

板凳
 
多谢分享!
此帖出自GD32 MCU论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

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