STC8A8K64S4A12通过SPI接口操作基于ST7920的LCD12864液晶模块

文章地址:https://www.cnblogs.com/jqdy/p/12665430.html

1. 硬件连接

1.1 64引脚的STC8A8K64S4A12

  使用的是最小核心板,所以引脚皆引出可供使用。其他接口只有USB口,起到供电及下载烧写的作用。

1.2 12864液晶模块

  店家提供的使用说明较为杂乱,后续除模块信息外,关于控制芯片的内容均参考ST7920手册。

  • 显示控制芯片使用的是ST7920
  • 模块有20个外接引脚(见图2)
  • PCB背板有选择串口和并口的两组焊点,短接后可分别选择串口和并口
  • 背板有一个可调电阻,用以调节对比度

1.3 连接方式

  因为还有其他几个外接模块,显示模块采用并口会占用过多I/O口,所以采用SPI串口连接方式,连接示意图及照片图1、图2所示。

图1:连接示意图

图2:照片示意图

  其中有几点需要特别说明:

1.3.1 模块的RST复位引脚是否需要连接

  模块手册上明确说明上电后模块自动复位,开始将RST连接到GND没有发现问题,但在调试过程中发现,如果上一次程序跑飞,液晶模块显示满屏“雪花”(注意不是乱码),下次烧写后无论程序对错,屏幕基本上保持原样,会影响到思路判断,还以为是程序仍然没有调试正确。估计其原因是ST7920被跑飞的程序置于某种状态,不再接收正确的指令了。

  因此,在调试过程中还是要连上此脚加上复位功能。即便是正式发布的程序,在系统无断电机会时,为了避免潜在Bug的影响,还是加上复位控制为好。

  ST7920手册记载,RST为低电平复位,保持时间在10us以上。

1.3.2 ST7920片选引脚是否连接

  如果只有一个外设使用SPI总线,可以不用将CS连接到单片机,直接将CS连接到Vcc即可,CS高电平有效。SPI总线上的设备超过一个时,就需要单片机控制CS信号了。

1.3.3 单片机SPI接口的SS脚如何处理

  SPI控制寄存器SPCTL的B7位SSIG明确了SS的功能。SSIG英文全称应该是Selected Slave Ignore(杜撰),字面意思是“忽略被选为从机的信号”,即STC8是否允许其他设备通过拉低SS脚电平把自己作为从机,SSIG=0代表允许,SSIG=1代表不允许。因此,在STC8总是作为主机的情况下,可以不用连接SS脚,软件配置上有两种选择

  • SSIG=1,忽略SS脚信号的控制作用。这种情况下,SS脚是否能做他用有待验证。
  • SSIG=0,配合SPCTL的B4位MSTR=1来保持主机地位。

  ST7920就是被动接收信息,不会作为主机控制SPI总线,模块也没有提供响应的引脚,因此就ST7920而言不用连接SS脚。但是我计划SPI总线上还有其他设备有可能以主机身份存在,因此SS脚暂时悬空,程序中仍然配置SSIG=0。

1.3.4 电源电压问题

  模块手册明确使用电压3.3-5.3V,实际接到5V电源时背光明亮,3V时柔和舒适,除此之外还需要调整一下PCB背板上的对比度可调电阻,否则字迹显示不清楚。

2. STC8A8K64S4A12SPI接口配置及操作

  该芯片使用SPI接口需要4个步骤,之后就可传输数据了。可根据实际情况省略前两个步骤:

  • 选择I/O口
  • 选择I/O口工作模式
  • 配置SPI控制寄存器
  • 中断使能

2.1 接口配置

2.1.1 选择I/O

  该芯片可将SPI功能脚配置到四组不同的I/O口,可以根据需要进行选择,外设端口切换寄存器1“P_SW1”的B3和B2位SPI_S[1:0] (SPI_Select)就起到这个作用,详情见表1和表2。

  因为P7口的复用功能比较少,我先将SPI配置到P7上,即SPI_S=10。这两位的上电复位默认值为“00”,若忽略选择I/O口这一步,SPI的I/O口将被定位在P1的4个口上。

表1:SPI端口切换寄存器(表中第二个)

表2 SPI功能脚选择位

2.1.2 选择I/O口工作模式

  该芯片所有I/O口都有四种工作模式:准双向口、推挽输出、高阻输入和开漏输出,可根据需要进行选择。需要配置寄存器是P0M1、P0M0 – P7M1、P7M0,共8对分别对应P0~P7。这些端口上电复位值均为0,如果忽略该步骤,所有I/O口均工作在准双向模式。我的方案就是省略该步骤采用默认值,也就是说SPI的四个口都工作在准双向模式。

  P0~P7(P4没有4.5~4.7口)每个端口都有两个端口模式寄存器,例如:P0口的B7~B0位对应的两个模式寄存器是P0M1和P0M0的B7~B0位,这一对寄存器用来确定对应的I/O口工作在四种模式中的哪一种。PnM1.x和 PnM0.x(n=1~7)分别为:

  • 00:准双向口:灌电流20mA,拉电流270~150uA。可见准双向口提供的驱动能力是有较大差异的,某个口为0时可容纳20mA电流流入,为1时输出电流要小约100倍(74-133倍)
  • 01:推挽输出:向上拉输出,可达20mA,要加限流电阻
  • 10:高阻输入:电流既不能流入,也不能流出,需要配合外部电路实现0、1的功能
  • 11:开漏输出:外加上拉电阻时,即可输入也可输出,否则读不到外部状态,也对外输不出高电平

2.1.3 配置SPI控制寄存器SPCTLSPI Control Register

  该寄存器的配置是操作SPI总线的重头戏,该寄存器的结构如表3所示。因为不用考虑兼容8051,SPI的所有控制位都集中到这个寄存器中。

表3 SPI三个寄存器的结构

  SPCTL共8个位,可以实现SPI总线7个方面的功能控制,为便于理解,下面尽可能用通俗的语言进行描述。

2.1.3.1 [B7]SSIGSelected Slave Ignore

  英文直译的意思是“忽略从设备选择信号”,芯片手册上称之为“SS引脚功能控制位”,但这个叫法不太容易理解,实际上就如本文1.1.3所言,其功能就是“是否允许其他设备通过拉低SS脚电平把自己作为从机”。

  SSIG的两种状态通俗的讲,就是话语权的问题,理解了这一点对“单主单从”、“互为主从”、“一主多从”的设置很关键:

  • 0:允许其他设备占主动权,若想将本机作为从机,其他设备将本机SS脚电平拉低就可实现这个目的。
  • 1:我永远占主动权,是主是从你们说了不算,我说了才算。让你们是从机的时候,你们就是从机,这时B4位MSTR=1,即表示我是主机,你们是从机;让你们是主机的时候,你们才能是主机,这时B4位MSTR=0,表示我是从机。

2.1.3.2 [B6]SPENSPI Enable

  SPI使能控制位,0=关闭SPI功能,1=使能。

2.1.3.3 [B5]DORDData Order

  数据位收发时的顺序,0=先高位MSB,1=先低位(LSB)。ST7920要求先高后低,因此该位应该设为0。

2.1.3.4 MSTRMaster

  MSTR:器件主/从模式选择位,SSIG章节已经掰嗤清楚了,这里不说了,抄手册。

  设置主机模式:

  • 若 SSIG=0,则 SS 管脚必须为高电平且设置 MSTR 为 1
  • 若 SSIG=1,则只需要设置 MSTR 为 1(忽略 SS 管脚的电平)

  设置从机模式:

  • 若 SSIG=0,则 SS 管脚必须为低电平(与 MSTR 位无关)
  • 若 SSIG=1,则只需要设置 MSTR 为 0(忽略 SS 管脚的电平)

2.1.3.5 [B3] CPOLClock PolaritySPI时钟极性控制)与[B2] CPHAClock PhaseSPI时钟相位控制)

  CPOL:SPI 时钟极性控制。

  • 0:SCLK 空闲时为低电平,SCLK 的前时钟沿为上升沿,后时钟沿为下降沿
  • 1:SCLK 空闲时为高电平,SCLK 的前时钟沿为下降沿,后时钟沿为上升沿

  CPHA:SPI 时钟相位控制

  • 0:数据 SS 管脚为低电平驱动第一位数据并在 SCLK 的后时钟沿改变数据,前时钟沿采样数据(必 须 SSIG=0)
  • 1:数据在 SCLK 的前时钟沿驱动,后时钟沿采样

  手册中给出的描述很简单,但是理解起来很是困难,有一篇帖子说的再明白不过了,摘抄了一张图稍作修改(图3),原文链接:高手带你理解SPI中的极性CPOL和相位CPHA

图3:SPI时钟极性与相位示意图

  我在这里遇到理解障碍主要有两点,对于判断这两位的高低十分重要。

  1. 手册中说的SCLK空闲时间指的是什么时间?

  答:指的是SPI总线启动前的时间。以ST7920为例,其时序图如图4所示,图中的时间是我根据手册数据加上去的。传输数据之前SCLK处于高电平状态,即极性CPOL=1。可恨的是手册写的水平不高,也可能是我理解能力有限,手册还给出了一张图(图5),正好拧着,好坑人。

图4:ST7920串口时序图

图5:坑人的另一张图

  2.       哪里算作SCLK的开始时间?

  明确开始时间,才能搞清楚哪里是第一个时钟沿,哪里是第二个时钟沿。搞清楚第一个问题后,这个问题就十分容易了。不难看出ST7920要求相位CPHA = 1。

2.1.3.6 SPR[1:0]

  英文应该是SPI Rate,即SPI时钟的波特率,占B1和B0两个位。手册给出的数值为:

  • 00:SYSclk÷4
  • 01:SYSclk÷8
  • 10:SYSclk÷16
  • 11:SYSclk÷32

  由此可见,在该单片机系统时钟固定的情况下,SPI时钟的波特率只有4种选择,分别是系统时钟的4、8、16、32分频。如果想使用其他频率,就必须调整系统时钟频率了。

  我选择的系统时钟频率是22.1184MHz,应该选择哪个分频还需要看ST7920的要求,ST7920在两种电压下对时钟周期的要求是不同的,见表4和表5。可见在工作电压越低,ST7920的工作速度越慢,在2.7V条件下的时钟周期Tscyc最小为600ns,在4.5V时最小为400ns。STC8A8K64S4A12的工作电压我选择的是3V,因此按照2.7V的600ns来计算肯定可以满足ST7920的要求。

1秒÷600纳秒=1.67MHz,这是ST7920要求的频率上限。

  有了这个数就好办了,一一计算22.1184MHz的四种分频,不难得出选择16分频为佳,22.1184 MHz÷16 = 1.3824MHz。因此SPR[1:0]的这两位选择10。

表4:ST7920在4.5V条件下的时间要求

表5:ST7920在2.7V条件下的时间要求

2.2 SPI中断的使能操作

  使能操作要简单的多,SPI的使能位在IE2的B1位------ESPI,见表6。先将ESPI=1,再打开总中断EA=1,就完成了SPI的使能操作。

表6:中断使能寄存器 IE2

2.3 SPI传输数据操作

  使用SPI传输数据涉及两个寄存器,就是表1中的状态寄存器SPSTAT(SPI Status Register)和数据寄存器SPDAT(SPI Data Register)。

  这里只有两点需要说明:

  1.       按说可以利用SPI中断自动实现SPI的数据传输,可我反复尝试最终失败了,还是选择了常规的发送数据后,等待中断产生,手工清除状态寄存器的方式。有可能是STC8手册《A.2 关于使用CLR指令关闭EA的重要说明》提到“使用4级流水线”的原因。

  2.       状态寄存器标识位的清零需要写1(SPSTAT = 0xc0),不能使用常规的清零方法(SPSTAT = 0)。

3. ST7920的操作

  SPI串口设置好了,就可以根据ST7920手册要求顺利操作了,网上的例子也多。

  这里需要说明的是:

  1、 选择串口方式,需要将背板上的“S”点,用焊锡短接,见图6。这一点根据模块不同可能有不同的方式。

图6 模块PCB背板局部

  2 、网上的例子中每次操作ST7920配的延时时间各不相同,我尝试了一下,各种保证手册要求的72us即可(清屏操作需等待1.6ms)。这有可能与采用的显示控制芯片有关。

  3 、串口方式向ST7920发送命令或数据的步骤

  发送每个命令或数据都要发送三个字节的信息:

  • 第一个字节:启动字节。若后面跟的是命令,启动字节=0xf8;后面跟的是数据启动字节=0xfa。
  • 第二、三个字节:要发送的命令或数据。原本命令或数据都是一个字节8位的,发送时需要拆成两次发送,第二个字节的高4位是命令或数据字节的高4位,第三个字节的高4位是命令或数据字节的低4位,空出来的位均为0。

  4 、关于DDRAM地址与屏幕坐标的关系

  这一点手册中说的也不太清楚,用表格表示一下,见表7。表中的数字均为16进制,例如80表示0x80;每个地址应该是个16位数,以0x80为例说明,高8位表中用80.H表示,低8位表中用80.L表示。

表7 屏幕坐标和DDRAM地址的对应关系

4 主要程序

  因为我使用Visual Studio 2019作为编辑器,所以使用了更多的VS习惯,以便更多的利用VS的自动提示功能。如何在VS中编辑,在Keil中调试请见:如何发挥Visual Studio 2019强大的编辑功能轻松编辑Keil项目

 1 //SPI配置
 2 #include <STC8.H>
 3 #include "System.h" //主要定义了unsigned char为u8等等
 4
 5 /// <summary>
 6 /// SPI单主多从模式的主机初始化
 7 /// </summary>
 8 /// <param name="dataOrder">传输字节哪头优先</param>
 9 /// <param name="clockPolarity">时钟极性控制</param>
10 /// <param name="clockPhase">时钟相位控制</param>
11 /// <param name="spiSpeed">时钟频率</param>
12 /// <param name="pinSelect">功能脚组别选择</param>
13 /// <returns></returns>
14 void STC8_SPI_One_Master_Many_Slave_Init(u8 dataOrder, u8 clockPolarity, u8 clockPhase, u8 spiSpeed, u8 pinSelect )
15 {
16     // 第一步:选择输出脚
17     P_SW1 &= 0xf3; // P_SW1同时还负责着串口1、CCP的管脚选择,注意不能覆盖
18     P_SW1 |= pinSelect;
19     //第二步:配置IO脚工作模式为准双向口/弱上拉,即处于00
20     //第三步:控制寄存器配置
21     SPCTL = 0x50;
22     SPCTL |= (dataOrder | clockPolarity | clockPhase | spiSpeed);
23     SPSTAT = 0xc0; //写1清零
24     IE2 |= ESPI; //使能SPI中断
25     EA = 1;
26 }

  上边程序片段用的到几个宏在包含文件中:

#include "System.h"
#define STC8_SPI_PIN_P12_P13_P14_P15 0x00 // SPI输出脚按顺序分别是SS/MOSI/MISO/SCLK
#define STC8_SPI_PIN_P22_P23_P24_P25 0x04 // SPI输出脚按顺序分别是SS/MOSI/MISO/SCLK
#define STC8_SPI_PIN_P74_P75_P76_P77 0x08 // SPI输出脚按顺序分别是SS/MOSI/MISO/SCLK
#define STC8_SPI_PIN_P35_P34_P33_P32 0x0c // SPI输出脚按顺序分别是SS/MOSI/MISO/SCLK

#define STC8_SPI_DATA_ORDER_MSB_FIRST 0x00 // SPI传送字节高位在先,0000 0000
#define STC8_SPI_DATA_ORDER_LSB_FIRST 0x20 // SPI传送字节低位在先,0010 0000
#define STC8_SPI_POLARITY_IDLE_LOW 0x00 // SPI时钟空闲时低电平,0000 0000
#define STC8_SPI_POLARITY_IDLE_HIGH 0x08 // SPI时钟空闲时高电平,0000 1000
#define STC8_SPI_PHASE_SAMPLING_FIRST_EDGE 0x00 // 在第一个时钟沿采样    ,0000 0000
#define STC8_SPI_PHASE_SAMPLING_SECOND_EDGE 0x04 // 在第二个时钟沿采样,0000 0100
#define STC8_SPI_SPEED_SYSCLOCK_DIVIDE_4 0x00 // SCLK频率为SYSclk 4分频,0000 0000
#define STC8_SPI_SPEED_SYSCLOCK_DIVIDE_8 0x01 // SCLK频率为SYSclk 8分频,0000 0001
#define STC8_SPI_SPEED_SYSCLOCK_DIVIDE_16 0x02 // SCLK频率为SYSclk 16分频,0000 0010
#define STC8_SPI_SPEED_SYSCLOCK_DIVIDE_32 0x03 // SCLK频率为SYSclk 32分频,0000 0011

/// <summary>
/// SPI单主多从模式的主机初始化
/// </summary>
/// <param name="dataOrder">传输字节哪头优先</param>
/// <param name="clockPolarity">时钟极性控制</param>
/// <param name="clockPhase">时钟相位控制</param>
/// <param name="spiSpeed">时钟频率</param>
/// <param name="pinSelect">功能脚组别选择</param>
/// <returns></returns>
void STC8_SPI_One_Master_Many_Slave_Init(u8 dataOrder, u8 clockPolarity, u8 clockPhase, u8 spiSpeed, u8 pinSelect);

  ST7920的主要部分:

  1 #include <STC8.H>
  2 #include "System.h"
  3 #include "Common.h" //主要定义了延时函数
  4
  5 #define COMMAND_CODE 0xf8 // 命令首字节
  6 #define DATA_CODE 0xfa //数据首字节
  7
  8 #define CSEN 1 //ST7920片选有效为高电平
  9 #define CSDS 0
 10
 11 #define DELAY_TIME 72 // 除Clear外所有命令都需要72us延时,专门定义宏,需要时好调整
 12
 13 sbit rst = P7 ^ 2; //12864复位信号,复位低电平有效,持续时间10us
 14 sbit cs = P7 ^ 3; //12864片选定义在P7.3
 15
 16 /// <summary>
 17 /// ST7920硬复位
 18 /// </summary>
 19 /// <returns></returns>
 20 void ST7920_Reset()
 21 {
 22     rst = 0;
 23     DelayUs_1T_221184(10);
 24     rst = 1;
 25     DelayMs_1T_221184(40); //复位40毫秒后系统可用
 26 }
 27
 28 void wrt_byte(u8 byte)
 29 {
 30     cs = CSEN;
 31     IE2 &= 0xfd; //关SPI中断
 32     SPDAT = byte;
 33     while (!(SPSTAT & 0x80));
 34     SPSTAT = 0xc0; //写1清零
 35     IE2 |= ESPI; //STC8.H定义ESPI = 0x02
 36     cs = CSDS;
 37 }
 38
 39 /// <summary>
 40 /// 向ST7920发送命令字节
 41 /// </summary>
 42 /// <param name="cmd">命令字节</param>
 43 /// <returns></returns>
 44 void ST7920_SendCommand(u8 cmd)
 45 {
 46     wrt_byte(COMMAND_CODE);//命令首字节
 47     wrt_byte(cmd & 0xf0);//命令字节高4位
 48     wrt_byte(cmd << 4); //命令字节低4位
 49     DelayUs_1T_221184(DELAY_TIME);//7920要求72us
 50 }
 51
 52 /// <summary>
 53 /// 向ST7920发送数据字节
 54 /// </summary>
 55 /// <param name="cmd">数据字节</param>
 56 /// <returns></returns>
 57 void ST7920_SendData(u8 data_)
 58 {
 59     wrt_byte(DATA_CODE);//数据首字节
 60     wrt_byte(data_ & 0xf0); //数据字节高4位
 61     wrt_byte(data_ << 4); //数据字节低4位
 62     DelayUs_1T_221184(DELAY_TIME);//7920要求72us
 63 }
 64
 65
 66 /// <summary>
 67 /// 功能同ST7920_SetDDRAMAddrss(),只是把类似于0x80的地址转变成行和列,基本指令集
 68 /// </summary>
 69 /// <param name="row">行数(0-3)</param>
 70 /// <param name="col">列数(0-15)</param>
 71 /// <returns></returns>
 72 void ST7920_SetDisplayPosition(u8 row, u8 col)
 73 {
 74     u8 address;
 75     if (row == 0x00) address = 0x80;
 76     if (row == 0x01) address = 0x90;
 77     if (row == 0x02) address = 0x88;
 78     if (row == 0x03) address = 0x98;
 79     address += col;
 80     ST7920_SendCommand(address);
 81 }
 82
 83 /// <summary>
 84 /// 写16×16点阵全宽字形(CGRAM:0000H、0002H、0004H、0006H;CGROM:A1A0H-F7FFH(GB)或A140H-D75FH(BIG5) )
 85 /// </summary>
 86 /// <param name="hByte">高8位字形编码</param>
 87 /// <param name="lByte">低8位字形编码</param>
 88 /// <returns></returns>
 89 void ST7920_DisplayChar_16_16(u8 hByte, u8 lByte)
 90 {
 91     ST7920_SendData(hByte);
 92     ST7920_SendData(lByte);
 93 }
 94
 95 void ST7920_DisplayString_16_16(u8 * str, u8 lenth)
 96 {
 97     u8 i = 0;
 98     for (; i < lenth; i += 2)
 99     {
100         ST7920_SendData(str[i]);
101         ST7920_SendData(str[i + 1]);
102     }
103 }

  上面代码用的的包含文件:

 1 #include "System.h"
 2 #include "Common.h"
 3
 4 /// <summary>
 5 /// ST7920硬复位
 6 /// </summary>
 7 /// <returns></returns>
 8 void ST7920_Reset();
 9
10 /// <summary>
11 /// 发送命令
12 /// </summary>
13 /// <param name="data_">要发送的命令</param>
14 /// <returns></returns>
15 void ST7920_SendCommand(u8 cmd);
16
17 /// <summary>
18 /// 发送数据到内部 RAM ( DDRAM/CGRAM/IRAM/GRAM)
19 /// </summary>
20 /// <param name="data_">要发送的数据</param>
21 /// <returns></returns>
22 void ST7920_SendData(u8 data_);
23
24 //基本指令集
25 #define ST7920_Clear() do{ST7920_SendCommand(0x01);DelayMs_1T_221184(2);}while(0) // 清屏,7920要求延时1.6ms(基本指令集)
26 #define ST7920_HOME 0x02 // 地址归位,基本指令集,DDRAM的地址计数器AC到00H
27 #define ST7920_DISPLAY_NORMAL 0x0c // 整体显示开,游标关,反白关(基本指令集),总功能:0000 1D(1/0,总体显示开/关)C(1/0,游标开/关)B(1/0,游标位置反白开/关)
28 #define ST7920_ENTRY_NORMAL 0x06 // 游标及显示右移一次(基本指令集)
29 #define ST7920_XX 0x10 // 不理解,待后续试验观察
30 #define ST7920_BASIC_INSTRUCTION 0x30 // 选择8位数据接口的基本指令集
31 #define ST7920_EXTENDED_INSTRUCTION 0x34 // 选择8位数据接口的扩展指令集
32 #define ST7920_SetCGRAMAddress(address) do{ST7920_SendCommand(0x40+address);}while(0) //设定CGRAM地址
33 #define ST7920_SetDDRAMAddress(address) do{ST7920_SendCommand(address);}while(0) //将显存DDRAM地址设置到地址计数器AC,基本指令集。范围:第1行:80H-8FH,第2行:90H-9FH,第3行:A0H-AFH,第4行:B0H-BFH
34 #define ST7920_DisplayChar_16_8(char_) do{ST7920_SendData(char_);}while(0) //写16×8半宽字形(HCGROM:02H-7FH)
35
36 /// <summary>
37 /// 功能同ST7920_Set_DDRAM_Addrss(),只是把类似于0x80的地址转变成行和列,基本指令集
38 /// </summary>
39 /// <param name="row">行数(0-3)</param>
40 /// <param name="col">列数(0-15)</param>
41 /// <returns></returns>
42 void ST7920_SetDisplayPosition(u8 row, u8 col);
43
44 /// <summary>
45 /// 写16×16点阵全宽字形(CGRAM:0000H、0002H、0004H、0006H;CGROM:A1A0H-F7FFH(GB)或A140H-D75FH(BIG5) )
46 /// </summary>
47 /// <param name="hByte">高8位字形编码</param>
48 /// <param name="lByte">低8位字形编码</param>
49 /// <returns></returns>
50 void ST7920_DisplayChar_16_16(u8 hByte, u8 lByte);
51
52 /// <summary>
53 /// 写16×16点阵全宽字形字符串(CGRAM:0000H、0002H、0004H、0006H;CGROM:A1A0H-F7FFH(GB)或A140H-D75FH(BIG5) )
54 /// </summary>
55 /// <param name="str">字符串指针</param>
56 /// <param name="lenth">字符串长度(一个全宽字形长度为2)</param>
57 /// <returns></returns>
58 void ST7920_DisplayString_16_16(u8 *str, u8 lenth);

  主程序:

 1 #include "system.h"
 2 #include "STC8_SPI.h"
 3 #include "st7920.h"
 4 #include "Common.h"
 5
 6 /// <summary>
 7 /// ST7920初始化
 8 /// </summary>
 9 /// <returns></returns>
10 void ST7920_Init()
11 {
12     DelayMs_1T_221184(50);//该显示模块要求上电后延迟40ms
13     ST7920_SendCommand(ST7920_BASIC_INSTRUCTION); //基本指令集
14     ST7920_SendCommand(ST7920_DISPLAY_NORMAL);//显示开,游标关,反白关
15     ST7920_Clear(); // 用空格清屏
16     ST7920_SendCommand(ST7920_ENTRY_NORMAL); // 读写后游标及显示右移
17 }
18
19 unsigned char str[] = "配置接口";
20
21 void main()
22 {
23     STC8_SPI_One_Master_Many_Slave_Init(    //配置ST7920SPI接口
24         STC8_SPI_DATA_ORDER_MSB_FIRST,
25         STC8_SPI_POLARITY_IDLE_HIGH,
26         STC8_SPI_PHASE_SAMPLING_SECOND_EDGE,
27         STC8_SPI_SPEED_SYSCLOCK_DIVIDE_16,
28         STC8_SPI_PIN_P74_P75_P76_P77);
29     ST7920_Init();
30     ST7920_SetDisplayPosition(0, 0);
31     ST7920_DisplayString_16_16("要以热爱祖国为荣", 16);
32     ST7920_SetDisplayPosition(1, 0);
33     ST7920_DisplayString_16_16("祖国就是我们母亲", 16);
34     ST7920_SetDisplayPosition(2, 0);
35     ST7920_DisplayString_16_16("无私奉献报效祖国", 16);
36     ST7920_SetDisplayPosition(3, 0);
37     ST7920_DisplayString_16_16("这是每个公民责任", 16);
38     while (1);
39 }
40 //SPI中断
41 void SPI_Interrup() interrupt 9
42 {
43     SPSTAT = 0xc0; //写1清零
44 }

5 显示效果

原文地址:https://www.cnblogs.com/jqdy/p/12665430.html

时间: 2024-10-12 02:49:07

STC8A8K64S4A12通过SPI接口操作基于ST7920的LCD12864液晶模块的相关文章

基于MT7688 原厂SDK 使用SPI控制器驱动TFT屏幕ILI9225驱动器(spi接口)

以下是我的一个利用SPI控制器操作屏的一个操作实例 包含一个bpeer_tft.c 和一个bpeer_tft.h 这是我基于flash驱动剥离出来的spi控制器驱动 好的话,顶起来~~~~~~~~~~~~~~~~~~~ 下面是代码: bpeer_tft.c 1 /* 2 * MTD SPI driver for ST M25Pxx flash chips 3 * 4 * Author: Mike Lavender, [email protected] 5 * 6 * Copyright (c)

SPI、I2C、UART三种串行总线协议的区别和SPI接口介绍(转)

SPI.I2C.UART三种串行总线协议的区别 第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART(Universal Asynchronous Receiver Transmitter:通用异步收发器) 第二,区别在电气信号线上: SPI总线由三条信号线组成:串行时钟(SCLK).串行数据输出(SDO).串行数据输入(SDI).SPI总线可以实现多个SPI设备互相连接.提供SPI串行时钟的SPI

STM32——SPI接口

STM32--SPI接口 宗旨:技术的学习是有限的,分享的精神的无限的. 一.SPI协议[SerialPeripheral Interface] 串行外围设备接口,是一种高速全双工的通信总线.在ADC/LCD等与MCU间通信. 1.SPI信号线 SPI 包含 4 条总线,SPI 总线包含 4 条总线,分别为SS .SCK.MOSI.MISO. (1)SS(SlaveSelect):片选信号线,当有多个 SPI 设备与 MCU 相连时,每个设备的这个片选信号线是与 MCU 单独的引脚相连的,而其他

XML编程总结(五)——使用StAX接口操作xml

(五)使用StAX接口操作xml StAX,全称Streaming API for XML,一种全新的,基于流的JAVA XML解析标准类库.其最终版本于 2004 年 3 月发布,并成为了 JAXP 1.4(将包含在即将发布的 Java 6 中)的一部分.在某种程度上来说,StAX与SAX一样是基于XML事件的解析方式,它们都不会一次性加载整个XML文件.但是它们之间也有很大的不同. StAX和SAX的区别——拉式解析器和推式解析器的区别 虽然StAX与SAX一样基于XML事件解析,相比于DO

无限可能!为MT7620添加N个SPI接口

前言 我的上一篇文章中谈到,如何使能mt7620的第二个spi接口.既然第二个spi接口已经开放成功,那么,可否接着添加第三个.第四个spi接口呢?熟悉mt7620硬件的朋友一定会第一时间站出来反对我:怎么可能!?mt7620总共才两个spi接口,怎么可能添加更多呢?除非在硬件上想办法.然而我总是善于将不可能变为可能^_^,今天我就要和大家分享一下,如何不改动任何硬件,通过修改驱动的方法,实现多个spi接口.注意,我这里实现的spi,并非用gpio口模拟的bitbang伪spi,而是基于硬件sp

如何从Cortex-m向STM32移植使用SPI接口协议

/***************************************************************************************************** * @brief: LDC1000应用程序 * _____________ _______________ * |PB4(SSI2CLK) ----> SCLK| * |PB5(SSI2FSS) ----> CSB | * |PB6(SSI2RX)    <----       SDO

嵌入式物联网之SPI接口原理与配置

本实验采用W25Q64芯片 W25Q64是华邦公司推出的大容量SPI FLASH产品,其容量为64Mb.该25Q系列的器件在灵活性和性能方面远远超过普通的串行闪存器件.W25Q64将8M字节的容量分为128个块,每个块大小为64K字节,每个块又分为16个扇区,每个扇区4K个字节.W25Q64的最小擦除单位为一个扇区,也就是每次必须擦除4K个字节.所以,这需要给W25Q64开辟一个至少4K的缓存区,这样必须要求芯片有4K以上的SRAM才能有很好的操作. W25Q64的擦写周期多达10W次,可将数据

XML编程总结(三)——使用SAX接口操作xml

(三)使用SAX接口操作xml SAX解析器被称为SAXParser,SAXParser是由javax.xml.parsers.SAXParserFactory创建的.与DOM解析器不同,SAX解析器并不创建XML文档的内存表示,因此会占用更少的内存.SAX解析器通过调用回调方法(事件驱动)将XML文档结构通知客户端,也就是通过调用提供给SAXParser的org.xml.sax.helpers.DefaultHandler处理器内的方法. org.xml.sax.helpers.Default

XML编程总结(二)——使用DOM接口操作xml

(二)使用DOM接口操作xml DOM解析器将整个XML文档加载到内存中,使用DOM模型对XML文档在内存中建模.DOM解析器被称为DocumentBuilder,它位于javax.xml.parsers包下.下面是使用DOM对xml文档进行CRUD操作的演示. 测试类代码:Source和Result接口的使用,将内存中xml模型输出 1 public class DomTest { 2 private Document document; 3 4 @Before 5 public void s