最近项目上,由于一些变更问题,导致硬件设计上未考虑到相关GPIO是否支持硬件驱动,考虑到这两个驱动的应用场景并不普遍,基本上只有在下电与Boot升级时才可以会被应用(相信有经验的朋友以及猜出来是什么功能了),具体功能就不详说了,我们直接讲解关于IIC与SPI的模拟驱动吧。
1、IIC是什么?
解:IIC时双向二线制同步串行总线,用于连接微控制器及其外围设备。I2C总线仅需要两根线(SDA和SCL)即可在多个设备之间进行通信。
2、IIC的特点是什么?
解:以下是与软件相关的关键特性:
线少:仅使用两根线,一根串行数据线SDA(数据传输),一份串行时钟线SCL(同步数据传输);
多主多从:在IIC总线上可以存在一个或者多个主设备和多个从设备。主设备负责启动数据传输时产生的时钟信号,所以一般主设备是的微控制器;
软件寻址:IIC总线的从设备都有一个唯一地址标识,具体地址通常是硬件设计时对从设备外围电路的逻辑控制。而主设备就是通过这些地址选择访问指定的从设备;
多设备通信:多设备可以通过IIC总线实现通信,但同一时刻,只能允许一个主设备控制总线;
仲裁和握手:IIC有总裁机制,确保多主设备尝试控制总线时不会发生冲突。且通过确认ACK和否定确认NACK信号进行数据传输握手。
3、IIC通信过程
解:IIC通信过程分为:启动条件、地址传输、数据传输、停止条件。
启动条件:前面文章说过,IIC总线配置为开漏输出,不理解的朋友可以访问链接(https://blog.csdn.net/qq_40939768/article/details/142935984)看一下。所谓启动条件,就是通过将SDA从高电平拉到低电平,同时SCL线保持高电平来发起一个起始条件。
地址传输:主设备发送一个从设备地址,以沟通相关的从设备,后面再跟一个读写位,告诉从设备是读操作还是写操作。
数据传输:以8bit数据进行,每次传输都会有一个应答周期。
停止条件:主设备通过将SDA从低电平拉到高电平,同时SCL保持高电平来发起停止条件,结束数据传输。
4、为什么要用IO模拟IIC?
解:在嵌入式开发中,作为软件工程师,理想状态肯定是使用可以复用相关功能的IO编写相关驱动,如:IIC就使用支持硬件IIC的IO,这样做的好处是可以不用注意在传输过程由于一些其他操作(中断、任务抢占等等)影响通信质量等。
但是,在实际项目中,硬件设计时可能会考虑到PCB布线的其他原因,不得不修改使用其他Pin实现IIC或其他可用IO模拟的通信协议,同时相关功能在不影响系统的响应能力的情况下,就需要用IO模拟IIC驱动或其他驱动。
4、如何用IO模拟?
解:通过以上信息,理解能力稍强的朋友应该也明白其IIC总线的通信原理,理解能力稍弱的可以再多看几遍,IIC没有那么复杂。简而言之,就是控制IO的高低电平实现IIC通信。这里就不贴代码了,若有需要的朋友,可以评论或私信@我。我们主要讲下SPI的模拟。
5、IO模拟SPI代码实现
解:以下是关于IO模拟SPI的代码实现,可直接copy使用。需要了解SPI详细原理的朋友也可以私信或评论告知我。
#define SPI_MOSI_H /* MOSI拉高 */
#define SPI_MOSI_L /* MOSI拉低 */
#define SPI_SCK_H /* SCK拉高 */
#define SPI_SCK_L /* SCK拉低 */
#define SPI_CS_H /* CS拉高 */
#define SPI_CS_L /* CS拉低 */
#define SPI_MISO_READ /* 读取MISO状态 */
const Uint16 byDUMMY = 0xFFu; /* 虚拟字节 */
/**
* @FuncName: SPIWriteByte
* @Description: 写入1字节数据
* @Author:
* @Date:
* @param {Uint16} data
*/
static void SPIWriteByte(Uint16 data) {
Uint16 bitCount = 0u;
for (bitCount = 0u; bitCount < 8u; bitCount++) {
SPI_SCK_L; /* 设置时钟线低电平 */
/* 发送位 */
if (data & 0x80u) {
SPI_MOSI_H; /* 发送1 */
} else {
SPI_MOSI_L; /* 发送0 */
}
SPI_SCK_H; /* 设置时钟线高电平 */
data <<= 1u; /* 左移数据 */
}
}
/**
* @FuncName: SPIReadByte
* @Description: 读取1字节数据
* @Author:
* @Date:
*/
static Uint16 SPIReadByte(void) {
Uint16 data = 0u;
Uint16 bitCount = 0u;
for (bitCount = 0u; bitCount < 8u; bitCount++) {
SPI_SCK_L; /* 设置时钟线低电平 */
SPI_SCK_H; /* 设置时钟线高电平 */
data <<= 1u; /* 读取位 */
if (SPI_MISO_READ) {
data |= 0x01u;
}
}
return data;
}
标签:IIC,总线,SPI,IO,设备,define From: https://blog.csdn.net/qq_40939768/article/details/142997031