|
【基于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的驱动代码放出来
- /**
- ****************************************************************************************
- *
- * @file lcd_12864.c
- *
- * [url=home.php?mod=space&uid=159083]@brief[/url] lcd_12864 driver.
- *
- * Copyright (C) TChip 2014
- *
- * $Rev: 1.0 $
- *
- ****************************************************************************************
- */
- /**
- ****************************************************************************************
- * @addtogroup SPI
- * @{
- ****************************************************************************************
- */
- /*
- * INCLUDE FILES
- ****************************************************************************************
- */
- #include "gd32f3x0.h" // Device header
- #include "systick.h"
- #include "oled.h"
- #include "oledfont.h"
- /*
- * MARCO VARIABLE DECLARATION
- ****************************************************************************************
- */
- #define TRANSFER_SIZE (1) /*! Transfer size */
- #define TRANSFER_BAUDRATE (1000000U) /*! Transfer baudrate - 500k */
- #define MASTER_TRANSFER_TIMEOUT (5000U) /*! Transfer timeout of master - 5s */
- /*
- * LOCAL VARIABLE DECLARATION
- ****************************************************************************************
- */
- //check spi status
- volatile uint8_t oled_rx_flag = 0;
- volatile uint8_t oled_tx_flag = 0;
- //双缓冲显存
- uint8_t OLED_GRAM1[9][128];
- uint8_t OLED_GRAM2[9][128];
- uint8_t* pGRAM_back;
- uint8_t* pGRAM_front;
- //Init the OLED
- //static uint8_t Init_buffer[] =
- //{
- // 0xAE ,//--turn off oled panel
- // 0x00 ,//---set low column address
- // 0x10 ,//---set high column address
- // 0x40 ,//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
- // 0x81 ,//--set contrast control register
- // 0xCF , // Set SEG Output Current Brightness
- // 0xA1 ,//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
- // 0xC8 ,//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
- // 0xA6 ,//--set normal display
- // 0xA8 ,//--set multiplex ratio(1 to 64)
- // 0x3f ,//--1/64 duty
- // 0xD3 ,//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
- // 0x00 ,//-not offset
- // 0xd5 ,//--set display clock divide ratio/oscillator frequency
- // 0x80 ,//--set divide ratio, Set Clock as 100 Frames/Sec
- // 0xD9 ,//--set pre-charge period
- // 0xF1 ,//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
- // 0xDA ,//--set com pins hardware configuration
- // 0x12 ,
- // 0xDB ,//--set vcomh
- // 0x40 ,//Set VCOM Deselect Level
- // 0x20 ,//-Set Page Addressing Mode (0x00/0x01/0x02)
- // 0x02 ,//
- // 0x8D ,//--set Charge Pump enable/disable
- // 0x14 ,//--set(0x10) disable
- // 0xA4 ,// Disable Entire Display On (0xa4/0xa5)
- // 0xA6 ,// Disable Inverse Display On (0xa6/a7)
- // 0xAF ,//--turn on oled panel
- //
- // 0xAF , /*display ON*/
- //};
- void ole_delay(uint32_t tick)
- {
- while(tick-- > 0) __NOP();
- }
- /*
- * GLOBAL VARIABLE DECLARATION
- ****************************************************************************************
- */
- #if (GD32_OLED)
- /**
- ****************************************************************************************
- * @brief SPI RX CALLBACK FUNCTION.
- * @description
- *
- ****************************************************************************************
- */
- void oled_read_done(void)
- {
- oled_rx_flag = 0;
- }
- /**
- ****************************************************************************************
- * @brief SPI TX CALLBACK FUNCTION.
- * @description
- *
- ****************************************************************************************
- */
- void oled_write_done(void)
- {
- oled_tx_flag = 0;
- }
- /**
- ****************************************************************************************
- * @brief Configure the SPI GPIO and set RS 、 RST GPIO output,Init them.
- * @description
- *
- ****************************************************************************************
- */
- void oled_io_config(void)
- {
- /* Configure SPI_MASTER pins: SCK and MOSI */
- gpio_af_set(OLED_SCLK,GPIO_AF_0,OLED_SCLK_PIN|OLED_SDIN_PIN);
- gpio_mode_set(OLED_SCLK,GPIO_MODE_AF,GPIO_PUPD_NONE,OLED_SCLK_PIN|OLED_SDIN_PIN);
- gpio_output_options_set(GPIOB,GPIO_OTYPE_PP,GPIO_OSPEED_10MHZ,OLED_SCLK_PIN|OLED_SDIN_PIN);
- //set the LCD_RS_PIN and LCD_RST_PIN an output
- gpio_mode_set(OLED_DC,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,OLED_DC_PIN|OLED_RST_PIN|OLED_CS_PIN);
- gpio_output_options_set(OLED_DC,GPIO_OTYPE_PP,GPIO_OSPEED_10MHZ,OLED_DC_PIN| OLED_RST_PIN|OLED_CS_PIN);
- gpio_bit_reset(OLED_DC,OLED_DC_PIN);
- gpio_bit_set(OLED_RST,OLED_RST_PIN);
- }
- void OLED_Set_Pos(unsigned char x, unsigned char y)
- {
- OLED_WR_Byte(0xb0+y,OLED_CMD);
- OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
- OLED_WR_Byte((x&0x0f)|0x01,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);
- } //更新显示
- }
- void OLED_WR_Byte(uint8_t dat,uint8_t cmd)
- {
- if(cmd)
- OLED_DC_Set();
- else
- OLED_DC_Clr();
- OLED_CS_Clr();
- //spi_write(QN_SPI1, buffer, 1, oled_write_done);
- spi_i2s_data_transmit(SPI0,dat);
- oled_write_done();
- //delay_10us(1);
- ole_delay(6);
- OLED_CS_Set();
- OLED_DC_Set();
- }
- void OLED_WR_Buffer(uint8_t* buffer,uint16_t bufLen,uint8_t cmd)
- {
- if(cmd)
- OLED_DC_Set();
- else
- OLED_DC_Clr();
- OLED_CS_Clr();
- //spi_write(QN_SPI1, buffer, 1, oled_write_done);
- for(int i=0; i<bufLen; i++)
- {
- spi_i2s_data_transmit(SPI0,buffer[i]);
- ole_delay(2);
- }
- oled_write_done();
- //delay_10us(1);
- OLED_CS_Set();
- OLED_DC_Set();
- }
- void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr)
- {
- unsigned char c=0,i=0;
- c=chr-' ';//得到偏移后的值
- if(x>7) {
- x=0;
- y=y+2;
- }
- for(i=0; i<6; i++)
- pGRAM_back[128*x+y+i] = F6x8[c*6+i];
- }
- //显示一个字符号串
- void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr)
- {
- unsigned char j=0;
- while (chr[j]!='\0')
- {
- OLED_ShowChar(x,y,chr[j]);
- y+=8;
- if(y>120) {
- x += 1;
- y = 2;
- }
- j++;
- }
- }
- /***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
- void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
- {
- unsigned int j=0;
- unsigned char 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);
- }
- }
- }
- //更新显存到LCD
- void OLED_Refresh_Gram(void)
- {
- uint8_t buf[128];
- uint8_t i,n;
- for(i=0; i<8; i++)
- {
- for(n=0; n<128; n++)
- {
- buf[n] = pGRAM_front[128*i +n];//OLED_GRAM[n][i];
- }
- OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
- OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
- OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
- OLED_WR_Buffer(buf,128,OLED_DATA);
- }
- }
- void OLED_Refresh(void)
- {
- /*为了提高效率,设置成水平地址模式*/
- OLED_WR_Byte (0x20,OLED_CMD); //设置内存地址模式:水平地址
- OLED_WR_Byte (0x00,OLED_CMD);
- OLED_WR_Byte (0x21,OLED_CMD); //设置列开始和结束地址
- OLED_WR_Byte (0x00,OLED_CMD); //设置列的开始地址
- OLED_WR_Byte (0x7F,OLED_CMD); //设置列的结束地址
- OLED_WR_Buffer(pGRAM_front,1024,OLED_DATA);
- }
- void SPI_config(void)
- {
- spi_parameter_struct SPI_InitStructure;
- /* SPI0 配置*/
- SPI_InitStructure.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
- SPI_InitStructure.device_mode = SPI_MASTER;
- SPI_InitStructure.frame_size = SPI_FRAMESIZE_8BIT;
- SPI_InitStructure.nss = SPI_NSS_SOFT;
- SPI_InitStructure.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
- SPI_InitStructure.prescale = SPI_PSC_2;
- SPI_InitStructure.endian = SPI_ENDIAN_MSB;
- spi_init(SPI0, &SPI_InitStructure);
- spi_enable(SPI0);
- }
- //初始化SSD1306
- void OLED_Init(void)
- {
- oled_io_config();
- SPI_config();
- OLED_RST_Set();
- delay_1ms(10);
- OLED_RST_Clr();
- delay_1ms(10);
- OLED_RST_Set();
- pGRAM_back = (uint8_t*)OLED_GRAM1;
- pGRAM_front = (uint8_t*)OLED_GRAM2;
- 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_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
- OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/
- OLED_Clear();
- OLED_Set_Pos(0,0);
- }
- #endif
- ///end
复制代码
|
|