SPI(串行外设接口)是一种广泛应用的全双工同步串行通信协议,通常用于微控制器与外部设备之间的高速数据传输。它采用主从架构,通过主设备生成时钟信号并控制数据流动,通过四条主要信号线(MOSI、MISO、SCLK和SS)实现全双工通信。数据传输通过时钟的上升或下降沿进行,且支持可配置的时钟极性(CPOL)和相位(CPHA),以适应不同设备的要求。尽管SPI的传输速度较高,且实现相对简单,但其缺点在于需要较多的引脚和短距离传输的限制,适合用于传感器、存储器、显示屏及其他外设的接口。整体来说,SPI因其速度和灵活性在嵌入式系统中得到了广泛应用。
全双工:全双工指的是通信的双方可以同时进行数据的发送和接收,彼此互不干扰。(也就是说需要至少两条线进行通信)
同步:指数据的传输是通过一个共同的时钟信号进行协调的。所有参与通信的设备都依赖于同一时钟信号来发送和接收数据。
串行通信: 数据通过一条数据线依次一位一位的发送。
发送设备和接收设备在同一时刻依据同一个时钟信号进行数据的采样和传输。
SPI 协议通信过程
主设备选择从设备:通过将对应从设备的 SS 线拉低,选中某个从设备进行通信。
时钟同步:主设备生成 SCLK,并在时钟上升沿或下降沿驱动数据。
数据传输:
完成通信:数据传输结束后,主设备将 SS 线拉高,终止对从设备的选择。
通信过程图
MOSI: 主设备输出,从设备输入(接收)
MISO: 主设备输入(接收),从设备输出
SCLK: 主设备生成的时钟信号
SS(NSS): 选择从设备的的信号(当每次传输完成后,主设备拉高 SS 信号,结束通信)
OLED显示屏
本次示例屏采用的是中景园的 0.96 寸 OLED 显示屏 SSD1306 驱动带字库
如图所示
右图中左侧六个引脚的为字库芯片
右图中右侧三个引脚的为线性稳压器
引脚说明
GND:逻辑电路的接地端。必须连接到地。
VCC:OLED 的电源输入端。必须连接到电源。
CLK / SCL:串行时钟输入端。
MOSI / SDA:串行数据输入端。
DC:数据/命令控制引脚。当引脚拉高时,SDA输入作为显示数据处理;当引脚拉低时,SDA输入传递到命令寄存器。
CS1:OLED 芯片选择引脚;低电平使能,高电平禁止。
FSO:字库芯片的数据输出引脚。
CS2:字库芯片选择引脚;低电平使能,高电平禁止。
原理图
X096-2864KSWAG01:OLED 模块
8 * 2.54 :8个引脚,引脚间距为 2.54
GT20L16S1Y:字库 IC
ME6206a33XG:线性稳压器
函数先根据你要展示的内容,去字库芯片中查找他的位置,然从指定位置中读出这些字,然后展示在 OLED 上
STC8H
引脚图
字库 IC 中地址计算方法,以 GB2313为例
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
OLED_Display_GB2312_string(0,0,"12864,带中文字库");
u32 fontaddr=0; void OLED_Display_GB2312_string(u8 x,u8 y,u8 *text) { u8 i=0; u8 addrHigh,addrMid,addrLow; u8 fontbuf[32]; while(text[i]>0x00) { if((text[i]>=0xb0)&&(text[i]<=0xf7)&&(text[i+1]>=0xa1)) { fontaddr=(text[i]-0xb0)*94; fontaddr+=(text[i+1]-0xa1)+846; fontaddr=fontaddr*32; addrHigh=(fontaddr&0xff0000)>>16; addrMid=(fontaddr&0xff00)>>8; addrLow=(fontaddr&0xff); OLED_get_data_from_ROM(addrHigh,addrMid,addrLow,fontbuf,32); OLED_Display_16x16(x,y,fontbuf); x+=16; i+=2; } else if((text[i]>=0xa1)&&(text[i]<=0xa3)&&(text[i+1]>=0xa1)) { fontaddr=(text[i]-0xa1)*94; fontaddr+=(text[i+1]-0xa1); fontaddr=fontaddr*32; addrHigh=(fontaddr&0xff0000)>>16; addrMid=(fontaddr&0xff00)>>8; addrLow=(fontaddr&0xff); OLED_get_data_from_ROM(addrHigh,addrMid,addrLow,fontbuf,32); OLED_Display_16x16(x,y,fontbuf); x+=16; i+=2; } else if((text[i]>=0x20)&&(text[i]<=0x7e)) { unsigned char fontbuf[16]; fontaddr=(text[i]-0x20); fontaddr=(unsigned long)(fontaddr*16); fontaddr=(unsigned long)(fontaddr+0x3cf80); addrHigh=(fontaddr&0xff0000)>>16; addrMid=(fontaddr&0xff00)>>8; addrLow=fontaddr&0xff; OLED_get_data_from_ROM(addrHigh,addrMid,addrLow,fontbuf,16); OLED_Display_8x16(x,y,fontbuf); x+=8; i+=1; } else i++; } }
void OLED_WR_Byte(u8 dat,u8 cmd) { u8 i; if(cmd) { OLED_DC_Set(); } else { OLED_DC_Clr(); } OLED_CS_Clr(); for(i=0;i<8;i++) { OLED_SCL_Clr(); if(dat&0x80) { OLED_SDA_Set(); } else { OLED_SDA_Clr(); } OLED_SCL_Set(); dat<<=1; } OLED_CS_Set(); OLED_DC_Set(); }
void OLED_get_data_from_ROM(u8 addrHigh,u8 addrMid,u8 addrLow,u8 *pbuff,u8 DataLen) { u8 i; OLED_ROM_CS_Clr(); Send_Command_to_ROM(0x03); Send_Command_to_ROM(addrHigh); Send_Command_to_ROM(addrMid); Send_Command_to_ROM(addrLow); for(i=0;i<DataLen;i++) { *(pbuff+i)=Get_data_from_ROM(); } OLED_ROM_CS_Set(); }
u8 Get_data_from_ROM(void) { u8 i,read=0; for(i=0;i<8;i++) { OLED_SCL_Clr(); read<<=1; if(OLED_READ_FS0) { read++; } OLED_SCL_Set(); } return read; }
|
函数先根据你要展示的内容,去字库芯片中查找他的位置,然从指定位置中读出这些字,然后展示在 OLED 上
问题
一、SPI 和 UART 的区别
二、write 的代码也就是在控制数据点的高低,也没有显示的写入 OLED 的代码呀,为什么 OLED 可以保存并显示内容呢
在 OLED_WR_Byte()
函数中,虽然没有显式写入 SSD1306 内存的代码,但实际的数据传输是通过 SPI 或 I2C 接口的硬件控制实现的。
具体的写入过程
数据传输过程:
每个字节通过 SDA 引脚按位传输。OLED_SDA_Set()
和 OLED_SDA_Clr()
控制数据线的电平状态(高或低),代表传输的每一位。每次时钟 OLED_SCL_Set()
上升沿时,SSD1306 会读取数据引脚上的电平,形成一个位数据。
命令或数据的区分:
OLED_DC_Set()
和 OLED_DC_Clr()
用于区分当前传输的是数据还是命令。高电平表示数据,低电平表示命令。这决定了 SSD1306 如何处理接收到的信息。
**芯片选择 (CS)**:
OLED_CS_Clr()
拉低 CS 信号,告诉 SSD1306 开始通信。传输完成后,OLED_CS_Set()
结束通信。SSD1306 会根据传输的内容将数据存储到相应的显存地址中,并在下一个刷新周期内更新显示内容。
三、时钟极性*CKP/Clock Polarity)
四、时钟相位
SPI协议详解(图文并茂+超详细) - 知乎 (zhihu.com)