程序项目代做,有需求私信(vue、React、Java、爬虫、电路板设计、嵌入式linux等)

Mini2440裸机开发之SPI(OLED SSD1306)

通信协议-SPI小节,我们已经对SPI协议进行了详细的介绍,这里就不在重复赘述。

一、S3C2440上的SPI

1.1 SPI概述

SPI的使用位于S3C2440芯片手册的第23章。S3C2440包含了2个SPI,每个SPI都有2个分别分别用于发送和接收的8位串行移位寄存器。

一个SPI时钟周期,同时发送(串行移除)和接收(串行移入)一位数据,由相应控制寄存器设置指定8位串行数据的输出频率。

如果只希望发送数据,则接收数据可以保持伪位;如果只希望接收数据,则需要发送伪位'1'数据。

S3C2440 SPI特性:

  • 支持2个通道SPI;
  • 兼容SPI协议(2.11版本);
  • 8位发送串行移位寄存器;
  • 8位接收串行移位寄存器;
  • 8位预分频逻辑;
  • 查询、中断和DMA传输模式;

1.2 SPI方块图

S3C2440 SPI相关引脚定义:

SPI SCLK MOSI MISO SS
SPI0 GPE13 GPE12 GPE11 GPG2
SPI1 GPG7 GPG6 GPG5 GPG3

二、SPI相关寄存器

2.1 SPI控制寄存器SPCONn

寄存器 地址 R/W 描述 复位值
SPCON0 0x59000000 R/W SPI通道0控制寄存器 0x00
SPCON1 0x59000020 R/W SPI通道1控制寄存器 0x00

寄存器位信息: 

SPICONn 描述 初始状态
SMOD [6:5]

SPI模式选择,决定如何读/写SPTDAT

00:查询模式       01:中断模式

10:DMA模式      11:保留

00
ENSCK [4]

SCK使能

0:禁止     1:使能

0
MSTR [3]

主/从机选择

0:从机     1:主机

0
CPOL [2]

时钟极性选择,决定时钟是高电平有效还是低电平有效

0:高电平有效  1:低电平有效

0
CPHA [1]

时钟相位选择,和CPOL一起决定采样时刻

0:第一个边沿    1:第二个边沿

0
TAGD [0]

仅接收模式控制

0:正常收发   1:仅接收(此时自动发送任意数据)

在正常模式,如果只想接收数据,需要发送0xFF

0

2.2 SPI状态寄存器SPSTAn

寄存器 地址 R/W 描述 复位值
SPSTA0 0x59000004 R SPI通道0状态寄存器 0x01
SPSTA1 0x59000024 R SPI通道1状态寄存器 0x01

寄存器位信息: 

SPSTAn 描述 初始状态
保留 [7:3]

保留

-
DCOL [2]

数据冲突错误标志。如果当传输正在进行中写了SPTDATn或读了SPRDATn此标志置位,并且可以通过读取SPSTAn清除

0:无错误   1:发生冲突错误

0
MULF [1]

多主SPI错误标志

0:无错误   1:多主SPI错误

0
REDY [0]

收发就绪标志,此位表示SPTDATn或SPRDATn准备好了发送或者接收

0:未就绪    1:Tx/Rx就绪

1

2.3 SPI引脚控制寄存器SPPINn

寄存器 地址 R/W 描述 复位值
SPPIN0 0x59000008 R/W SPI通道0引脚控制寄存器 0x02
SPPIN1 0x59000028 R/W SPI通道1引脚控制寄存器 0x02

寄存器位信息: 

 

SPPINn 描述 初始状态
保留 [7:3]

保留

-
ENMUL [2]

多主机错误检测使能。当SPI系统为主机时,nSS引脚被用来作为输入检测多主机错误

0:禁止   1:使能

 
保留 [1]

保留

 
KEEP [0]

决定当1字节发送完成后MOSI的控制或释放(主机)

0:释放   1:保持之前的电平

 

2.4 SPI波特率预分频寄存器SPPREn

寄存器 地址 R/W 描述 复位值
SPPRE0 0x5900000C R/W SPI通道0波特率预分频寄存器 0x00
SPPRE1 0x5900002C R/W SPI通道1波特率预分频寄存器 0x00

 

寄存器位信息: 

SPPREn 描述 初始状态
保留 [7:0]

决定SPI时钟频率

波特率=PCLK/2/(预分频值+1)

0xxx

波特率应低于25MHz。

2.5 SPI发送数据寄存器SPTDATn

寄存器 地址 R/W 描述 复位值

SPTDAT0

0x59000010 R/W SPI通道0发送数据寄存器 0x00
SPTDAT1 0x59000030 R/W SPI通道1发送数据寄存器 0x00

寄存器位信息: 

SPTDATn 描述 初始状态
保留 [7:0]

包含通过SPI通道要发送的数据

0x00

2.6 SPI接收数据寄存器SPRDATn

寄存器 地址 R/W 描述 复位值

SPRDAT0

0x59000014 R/W SPI通道0接收数据寄存器 0xFF
SPRDAT1 0x59000034 R/W SPI通道1接收数据寄存器 0xFF

寄存器位信息: 

SPRDATn 描述 初始状态
保留 [7:0]

包含通过SPI通道接收到的数据

0xFF

三、读写操作流程 

3.1 初始化

3.1.1 IO引脚设置

设置SPIn引脚复用,这里我们以SPI通道1相关引脚为例:

  GPGCON &= ~((3<<6) | (3<<10) | (3<<12) | (3 <<14));    /* 清零 */
  GPGCON |= ((3<<6) | (3<<10) | (3 <<12) | (3 <<14));     /* 设置为SPI */
3.1.2 设置波特率预分频寄存器(SPPRE1)

由于我们PCLK=50HMz,因此当设置SPPRE1为4时,频率为$\frac{50MHz}{2*(4+1)}=5MHz$

  SPPRE1 = 4;

注意:设置波特率,需要根据威慑所能接收的范围来设置,比如查阅OLED的芯片手册得知其时钟最小值为100ns,即最大为10MHz。

3.1.3  配置SPCON1

配置查询模式;位[6:5]=00;

配置SCK输出使能;位[4]=1;

配置时钟极性、时钟相位;根据外接SPI设备来设置时钟极性,以及时钟相位,这里我们设置位[3:2]=00;

配置主机模式;位[1]=1;

配置正常收发模式;位[0]=0;

  SPCON1 = 0<<5 | 1<<4 | 1<<3 | 0<<2 | 0<< 1 | 0<<0;

初始化代码如下,这里代码包含了通过SPI控制器实现SPI通信,以及通过GPIO模拟SPI通信两种方式:

/*************************************************************
 *
 *  Function  : spi0初始化,GPG7 ~ SCLK  GPG6 ~ MOSI  GPG5 ~ MISO  GPG3 ~ SS
 *
 **************************************************************/
 void spi_init()
 {
 #ifdef GPIO_SPI
   /* IO配置 */
    GPGCON &= ~((3<<6) | (3<<10) | (3<<12) | (3 <<14));    /* 清零 */
    GPGCON |= ((1<<6) | (0<<10) | (1<<12) | (1 <<14));    /* 设置GPG5输入 GPG3、6、7为输出 */
 #else
    /* 1. IO配置 */
    GPGCON &= ~((3<<6) | (3<<10) | (3<<12) | (3 <<14));    /* 清零 */
    GPGCON |= ((1<<6) | (3<<10) | (3 <<12) | (3 <<14));     /* 设置GPG5、6、7为SPI、GPG3为输出 */
 
 
   /* 2. 设置波特率预分频寄存器  */
   SPPRE1 = 4;
 
    /* 3. 配置SPI  查询模式  SCK输出使能 时钟极性高电平有效 时钟相位第一个边沿  主机模式  正常收发 */
   SPCON1 = (0<<5) | (1<<4) | (1<<3) | (0<<2) | (0<< 1) | (0<<0);
 #endif
   GPGDAT |= (1<<3) ;                                     /* 取消片选 */
 }

需要注意的是,当采用SPI控制器实现SPI通信时,片选引脚GPG3是需要自己控制片选/取消片选的,这里经过测试发现如果GPG3引脚复用成nSS1是没有效果的。

3.2 发送数据

检查状态寄存器SPSTA1发送就绪标志位(REDY=1),并接着写数据到SPTDAT1;

/*************************************************************
*
*  Function  : 主设备发送一个字节
*  Input     : data 字节数据
*
**************************************************************/
void spi_write_byte(u8 data)
{
   int i;
   /* 选中 */
   spi_set_cs(0);

#ifdef GPIO_SPI
    for (i = 0; i < 8; i++){
        spi_set_clk(0);
        spi_set_mosi(data & 0x80);    /* 上升沿采样 输出最高位 */
        spi_set_clk(1);
        data <<= 1;
    }
#else
    /* 等待发送或接收 ready */
    while (!(SPSTA1 & 1));
    SPTDAT1 = data;
#endif

   /* 取消选中 */
   spi_set_cs(1);
}

GPIO模拟相关位操作代码:

/*************************************************************
*
*  Function  : 片选信号    GPG3引脚
*  Input     : val  0 选中   1 未选中
*
**************************************************************/
void spi_set_cs(char val)
{
    if (val)             /* 1 未选中 */
        GPGDAT |= (1<<3);
    else
        GPGDAT &= ~(1<<3);  /* 0 选中 */
}

/*************************************************************
*
*  Function  : GPIO模拟SPI时 设置时钟信号
*  Input     : val  0 低电平  1 高电平
*
**************************************************************/
void spi_set_clk(u8 val){
    if (val)                 /*1  高电平 */
        GPGDAT |= (1<<7);
    else                     /*0  低电平 */
        GPGDAT &= ~(1<<7);
}

/*************************************************************
*
*  Function  : GPIO模拟SPI时 设置MOSI
*  Input     : val  0 低电平  1 高电平
*
**************************************************************/
void spi_set_mosi(u8 val){
    if (val)                /*1  高电平 */
        GPGDAT |= (1<<6);
    else                    /*0  低电平 */
        GPGDAT &= ~(1<<6);
}

3.3 接收数据

正常收发方式(同时收发,TAGD=0):向数据发送寄存器SPTDAT1写0xFF,查询并确认 REDY为1,然后从数据接收寄存器中读取数据;

/*************************************************************
*
*  Function  : 主设备接收一个字节
*  Input     : data 字节数据
*
**************************************************************/
u8 spi_read_byte()
{
   u8 val = 0;
   /* 选中 */
   spi_set_cs(0);

#ifdef GPIO_SPI
    /* todo 未实现*/
#else
   /* 向数据发送寄存器SPTDAT1写0xFF */
   SPTDAT1 = 0xff;
    /* 等待发送或接收 ready */
    while (!(SPSTA1 & 1));
    val = SPRDAT1;
#endif
     /* 取消选中 */
    spi_set_cs(1);
}

仅接收方式(TAGD=1):并确认REDY为1,然后从数据接收寄存器中读取数据。读取数据的同时启动一次发送。

四、OLED128x64(SSD1306)

由于Mini2440开发板并没有外接SPI设备,因此我们只能通过开发板引脚外接SPI设备。

这里我们外接一款支持SPI通信的OLED,显示屏尺寸为0.96寸、OLED屏幕内部驱动IC为SSD1306,像素为128*64。

OLED 有机发光二极管,相比于LCD区别在于LCD需要背光,而OLED不需要,因为它是自发光的。

4.1 SSD1606介绍

SD1306是一款带控制器的用于OLED点阵图形显示系统的单片CMOS OLED/PLED驱动器。它由128个SEG(列输出)和64个COM(行输出)组成。该芯片专为共阴极OLED面板设计。

SSD1306内置对比度控制器、显示RAM(GDDRAM)和振荡器,以此减少了外部元件的数量和功耗。

该芯片有256级亮度控制,数据或命令由通用微控制器通过硬件选择的6800/8000系通用并行接口、I2C接口或串行外围接口发送。

该芯片适用于许多小型便携式应用,如手机副显示屏、MP3播放器和计算器等。

使用该芯片可通过硬件电阻连接选中使用三线SPI、四线SPI或IIC,如下图所示:

 至于为什么,我们可以在芯片datasheet上找到答案,SSD1306通过BS[2:0]引脚选择通信协议:

当选择不同的通信协议时,其数据引脚和控制引脚也略有差异:

4.2 引脚说明

当SSD1306选定4-wire serial interface接口方式,SPI引脚定义:

  • CS:片选信号;连接S3C2440的GPG3引脚;
  • DC::命令数据选择引脚;连接S3C2440的GPG10引脚;
  • RES:模块复位引脚,低电平有效;连接S3C2440的GPG9引脚;
  • D1:MOSI,SPI数据线,主设备输出从设备输入引脚;连接S3C2440的GPG6引脚;
  • D0:SCLK,SPI时钟线;连接S3C2440的GPG7引脚;
  • VCC:电源正极3.3~5V;
  • GND:电源地;

我们需要按照Mini2440的电路原理图去将oled引脚和开发板GPIO引脚连接起来。

4.3 显示原理

SSD1306使用GDDRAM保存要显示的数据,GCDRAN是未映射静态RAM。RAM的大小为128 x 64位,RAM分为8页,从第0页到第7页,用于单色128x64点阵显示。

每个点(像素)使用1位来表示,为1则亮,为0则灭。

当一个数据字节写入GDDRAM时,列被填充(即,由列地址指针指示的整列(8位)被填充)。数据位D0被写入顶行,而数据位D7被写入底行。

4.4 GDDRAM寻址模式

GDRAM有三种寻址模式,页寻址,水平寻址。垂直寻址。一般我们不修改其寻址模式,使用默认的页寻址,但当有数据更合适其它寻址方式时,可以更换寻址方式。

4.4.1 页寻址模式

页寻址模式是器件默认选择的GDDRAM寻址模式,通过“20H,02H”命令可以设置寻址模式为页寻址。

在页寻址模式下,寻址只在一页(PAGEn)内进行,地址指针不会跳到其它页。每次向GDDRAM写入1字节显示数据后,列指针会自动+1。

当128列都寻址完之后,列指针会重新指向SEG0而页指针仍然保持不变。通过页寻址模式我们可以方便地对一个小区域内数据进行修改。 

4.4.2 水平寻址

水平寻址模式可以通过指令“20H,00H”来设置。

水平寻址模式下,每次向GDDRAM写入1字节数据后,列地址指针自动+1。

列指针到达结束列之后会被重置到起始列,而页指针将会+1。

页地址指针达到结束页之后,将会自动重置到起始页。水平寻址模式适用于大面积数据写入,例如一帧画面刷新。 

4.4.3 垂直寻址

垂直寻址模式可以通过指令“20H,01H”来设置。

垂直寻址模式下,每次向GDDRAM写入1字节数据之后,页地址指针将会自动+1。

页指针到达结束页之后会被重置到0,而列指针将会+1。

列地址指针达到结束页之后,将会自动重置到起始列。

4.5 常用命令

 4.5.1 设置对比度

双字节指令:0x81H + A[7:0]

此命令设置显示器的对比度设置。该芯片具有从0x00H到0xFFh的256个对比度步长。这个段输出电流随着对比度阶跃值的增加而增加。

4.5.2 设置正常/反转显示

单字节指令:0xA6H / 0xA7H (正常/反转)

正常为1亮0灭,反转为1灭0亮。

4.5.3 设置寻址方式

单字节指令:0x20H + A[1:0]

A[1:0]为寻址方式,00为水平寻址,01为垂直寻址,02为页寻址。默认为02。

4.5.4 设置起始/结束列地址(21H)

三字节指令:0x21H + A[6:0] + B[6:0] (起始 + 终止)

A、B为需要设置的起始和结束坐标,最高位为无效位,即最高设置坐标为127。

4.5.5 设置起始/结束页地址

三字节指令:0x22H + A[2:0] + B[2:0](起始 + 终止)

A、B为需要设置的起始和结束坐标,仅低三位有效,即最高设置页为7。

注意:该三字节命令指定显示数据RAM的页起始地址和结束地址,该指令仅在垂直寻址和水平寻址模式下才有效。

4.5.6 设置列地址

单字节指令:0x00H / 0x10H (低/高)+ A[3:0] 

设置列地址需要发送两次命令,一次是设置列地址低4位,一次是设置列地址高四位。

A为需要设置列的坐标的低/高四位,(00h~0Fh)。

注意:该指令仅在设置页寻址模式下才有效

4.5.7 设置页地址

单字节指令: 0xB0H + A[3:0]

A为需要设置的页,最高为7。

注意:该指令仅在设置页寻址模式下才有效

4.5.8 设置显示开关

单字节指令:0xAEH / 0xAFH 

0xAEH:显示关,0xAF:显示开。

4.5.9 Entire Display ON

4.5.10 Set Display Start Line (40h~7Fh)

单字节指令: 0x40 ~0x7F

该命令通过从0到63选择一个值,设置显示起始行寄存器以确定显示RAM的起始地址。值等于0时,RAM行0映射到COM0。当值等于1时,RAM行1被映射到COM0,依此类推。

4.5.11 设置左右反置

单字节指令: 0xA0 /0xA1

 0xA0:正常,0xA1左右反置;

4.5.12 设置上下反置

单字节指令: 0xC0 /0xC8

0xC0:正常,0xC8上下反置;

五、oled示例代码

5.1 GPIO初始化

配置  GPG9、GPG10配置为输出,并且初始化SPI1:

/*************************************************************
*
*  Function  : 初始化oled使用到的所有引脚、初始化SPI1
*
**************************************************************/
void oled_gpio_init()
{
  /* 1. IO配置  GPG9、GPG10配置为输出 */
  GPGCON &= ~((3<<18) | (3<<20));    /* 清零 */
  GPGCON |= ((1<<18) | (1<<20));     /* 设置为输出 */
  GPGDAT |= ((1<<9) | (1<<10));


  /* 2. SPI1初始化  */
   spi_init();
}


/*************************************************************
*
*  Function  : oled复位信号    GPG9引脚
*  Input     : val  0 复位    1 取消复位
*
**************************************************************/
void oled_set_res(char val)
{
    if (val)             /* 1 取消复位 */
        GPGDAT |= (1<<9);
    else
        GPGDAT &= ~(1<<9);  /* 1 复位 */
}


/*************************************************************
*
*  Function  : oled数据/命令信号  GPG10引脚
*  Input     : val  0 命令   1 数据
*
**************************************************************/
void oled_set_dc(u8 val)
{
    if (val)                 /* 1 数据 */
        GPGDAT |= (1<<10);
    else
        GPGDAT &= ~(1<<10);   /* 0 命令*/
}

5.2 写命令

/*************************************************************
*
*  Function  : 通过SPI协议写命令
*  Input     : cmd  命令
*
**************************************************************/
void oled_write_cmd(u8 cmd)
{
  /* 写命令 */
  oled_set_dc(0);

  /* 发送数据 */
  spi_write_byte(cmd);

  /* gpio output default is pull up*/
  oled_set_dc(1);
}

5.3 写数据

/*************************************************************
*
*  Function  : 通过SPI协议写数据
*  Input     : data 数据
*
**************************************************************/
void oled_write_data(u8 data)
{
  /* 写数据 */
   oled_set_dc(1);

  /* 发送数据 */
  spi_write_byte(data);

  /* gpio output default is pull up*/
  oled_set_dc(1);
}

5.4 设置oled坐标 

/*************************************************************
*
*  Function  : 坐标设定
*  Input     : x x坐标
*              y y坐标
*
**************************************************************/
void oled_pos(u8 x,u8 y)
{
    oled_write_cmd(0xB0+y);
    oled_write_cmd(((x&0xF0)>>4)|0x10);            /* 设置列地址高四位 */
    oled_write_cmd(x&0x0F);                         /* 设置列地址低四位 */
}

 这里发送了两个命令一个是设置页地址,另一个是设置列地址。

5.5 清屏

/*************************************************************
*
*  Function  : 清屏
*
**************************************************************/
void oled_clear()
{
    u8 x;
    u8 y;
    for(y=0;y<8;y++)
    {
        oled_write_cmd(0xB0+y);            /* 选择页 */
        oled_write_cmd(0x00);              /* 设置列地址低四位 */
        oled_write_cmd(0x10);              /* 设置列地址高四位 */
        for(x=0;x<0x80;x++)
            oled_write_data(0x00);           /* 每次清1列 */
    }
}

5.6 oled初始化

/***************************************************************************************************
 *
 *      Function   :  oled初始化
 *
 **************************************************************************************************/
void oled_init()
{
    /* 复位 */
    oled_set_res(0);
    delay_ms(50);
    oled_set_res(1);

     oled_write_cmd(0xAE);            /* 显示关 */
     oled_write_cmd(0x00);            /* 设置列低位地址 */
     oled_write_cmd(0x10);            /* 设置列高位地址 */
     oled_write_cmd(0x40);            /* set start line address  Set Mapping RAM Display Start Line (0x00~0x3F) */
     oled_write_cmd(0X81);            /* 设置对比度 */
     oled_write_cmd(0xCF);            /* 值越大 越亮 */
     oled_write_cmd(0xA1);            /* 设置列左右反置     0xa0左右反置 0xa1正常 */
     oled_write_cmd(0xC8);            /* 设置行上下反置     0xc0上下反置 0xc8正常 */
     oled_write_cmd(0xA6);            /* 设置正常显示 */
     oled_write_cmd(0x20);            /* 设置页地址模式 (0x00/0x01/0x02) */
     oled_write_cmd(0x02);            /* 页寻址 */
     oled_write_cmd(0x8D);            /* 设置电荷磊开关 */
     oled_write_cmd(0x14);            /* 电荷磊开 */
     oled_write_cmd(0xA4);            /* 字符显示开关 0xA4:开  0xA5:关 */
     oled_write_cmd(0xA6);            /* 背景色显示开关  0xA6:关   0xA7:开 */
     oled_write_cmd(0xAF);            /* 显示开 */

    oled_clear();                     /* 初始清屏 */
    oled_pos(0,0);
}

5.7  显示字符

关于字符的显示这里不重复介绍了,具体可以查看Mini2440裸机开发之LCD编程(GB2312、ASCII字库制作)

5.7.1 一个ASCII字符8行6列
/***************************************************************************************************
 *
 *      Function   :  写入一组标准ASCII字符串 一个字节占8行6列
 *    Input      : x 设置列地址0~0X7F
 *                  y 设置页地址0~7
 *                str 要显示的字符
 *
 **************************************************************************************************/
void oled_p6x8str(u8 x,u8 y,u8 *str)
{
  u8 i=0;
  u8 j=0;
  u8 k=0;
  while (str[j]!='\0')
  {
    while((str[j]<0x20)||(str[j]>0x80))     /* 当写入的没有对应的点阵时 显示空格 */
          str[j]=32;
    k =str[j]-32;
    if(x>121)
    {
         x=0;
         y++;
    }
    oled_pos(x,y);                           /* 选中坐标 */
      for(i=0;i<6;i++)
         oled_write_data(ASCII6x8[k][i]);        /* 写入一个字节 */
      x+=6;
      j++;
  }
}
5.7.2 1个ASCII字符16行8列
/***************************************************************************************************
 *
 *      Function   :  写入一组标准ASCII字符串 一个字节占16行8列
 *    Input      : x 设置列地址0~0X7F
 *                  y 设置页地址0~7
 *                str 要显示的字符
 *
 **************************************************************************************************/
void oled_p16x8str(u8 x,u8 y,u8 *str)
{
    u8 i=0;
     u8 j=0;
     u8 k=0;
     while(str[j]!='\0')
     {
        while((str[j]<0x20)||(str[j]>0x80))     /* 当写入的没有对应的点阵时 显示空格 */
            str[j]=32;
        k=str[j]-32;
        if(x>120)                            /* 列溢出 写入下一页 */
        {
          x=0;
          y++;
        }
          oled_pos(x,y);                       /* 选中页和列坐标 */
        for(i=0;i<8;i++)                     /* 写入上八行 */
        {
         oled_write_data(ASCII16x8[k][i]);
        }
        oled_pos(x,y+1);
        for(i=0;i<8;i++)                     /* 写入下八行 */
        {
          oled_write_data(ASCII16x8[k][i+8]);
        }
        x+=8;                               /* x坐标右移8位 准备写入下一个字节 */
        j++;                                /* 下一个字符 */
     }
}
5.7.3 1个汉字8行16列
/***************************************************************************************************
 *
 *      Function   :  写入一组汉字 一个汉字占8行16列
 *    Input      : x 设置列地址0~0X7F
 *                  y 设置页地址0~7
 *                str 要显示的字符
 *
 **************************************************************************************************/
void oled_p8x16chi(u8 x,u8 y,u8 *str)
{
     u8 i=0;
     u8 j=0;
     u8 k=0;
     while(str[j]!='\0')
     {
        if(x>120)                            /* 列溢出 写入下一页 */
        {
          x=0;
          y++;
        }
          oled_pos(x,y);                       /* 选中页和列坐标 */
        for(i=0;i<16;i++)                     /* 写入字 */
        {
         oled_write_data(CHINESE8x16[k][i]);
        }
        x+=16;                               /* x坐标右移8位 准备写入下一个字节 */
        j+=2;                                /* 下一个字*/
        k++;
     }
}

5.8 测试代码

#include "led.h"
#include "common.h"
#include "uart.h"
#include "oled12864.h"

int main()
{
    u8 i = 0;
    vector_enable();

    led_init();
    uart_init();
    delay_ms(1000);
    printf("oled gpio inio ...\r\n");
    oled_gpio_init();
    printf("oled inio ...\r\n");
    oled_init();

    oled_p16x8str(45,0,"OLED");          /* 在第0页即第一行的第45列开始,显示字符串“OLED" */

    while(1)
    {
        led_turn(LED1);
        delay_ms(1000);
        oled_p16x8str(8,2,"I Love you");
        oled_p6x8str(16,5,"I Love you");
    }
    return 0;
}

将代码下载到Nand Flash,启动开发板运行输出如下:

如果出现花屏,考虑是不是oled连线接触不良。如果屏幕不亮,考虑电源或者程序,显示屏存在问题。

六、代码下载

Young / s3c2440_project【13.spi】

参考文章

[1]S3C2410 SPI在win ce下的编程(1)

[2]S3C2410 SPI在win ce下的编程(2)

[3]Mini2440 通过 SPI 操作 OLED (裸板下使用 SPI 控制器)

[4]第20课 SPI协议详解及裸机程序开发分析

posted @ 2021-10-26 19:53  大奥特曼打小怪兽  阅读(293)  评论(0编辑  收藏  举报
如果有任何技术小问题,欢迎大家交流沟通,共同进步