做网站需要的流程,网络营销中的四种方法,wordpress大改动,上海开艺设计集团有限公司目录
1. 简介
2. 硬件电路
移位示意图
3. SPI时序基本单元
3.1 起始条件
3.2 终止条件
3.3 交换一个字节#xff08;模式0#xff09;
3.4 交换一个字节#xff08;模式1#xff09;
3.5 交换一个字节#xff08;模式2#xff09;
3.6 交换一个字节模式0
3.4 交换一个字节模式1
3.5 交换一个字节模式2
3.6 交换一个字节模式3
4. 代码编写
4.1 引脚初始化
4.2 引脚置高低电平封装
4.2.1 SPI写SS引脚电平
4.2.2 SPI写SCK引脚电平
4.2.3 SPI写MOSI引脚电平
4.2.4 I2C读MISO引脚电平
4.3 SPI起始
4.4 SPI终止
4.5 SPI交换传输一个字节
4.5.1 模式0
4.5.2 模式1
4.5.2 模式2
4.5.2 模式3 1. 简介 SPISerial Peripheral Interface是由Motorola公司开发的一种通用数据总线。同步全双工。支持总线挂载多设备一主多从。
四根通信线SCKSerial Clock串行时钟线 MOSIMaster Output Slave Input主机输出从机输入 MISOMaster Input Slave Output主机输入从机输出 SSSlave Select从机选择若是有多个从机有几个从机就有几条SS线可见硬件电路中的连接图。
2. 硬件电路 所有SPI设备的SCK、MOSI、MISO分别连在一起 主机另外引出多条SS控制线分别接到各从机的SS引脚 输出引脚配置为推挽输出输入引脚配置为浮空或上拉输入。 移位示意图 工作原理假如主机想要发送一个字节给从机从机也想发送一个字节给主机开始当SCK处于上升沿移位寄存器最左边数据移出例如SPI主机中移位寄存器最左边“1”移出到MOSI引脚上而SPI从机的移位寄存器的最左边的数据“0”移出到MISO引脚上当SCK处于下降沿MOSI上的数据进入到SPI从机的移位寄存器最右边MISO上的数据进入到SPI主机的移位寄存器最右边。往复八次经过时钟的上升沿和下降沿即可完成相互发送一个字节数据。 当多个从机输出连在一起如果同时开启输出会造成冲突解决方法是当SS未被选中的状态从机的MISO引脚必须关断输出即配置为高阻态。
3. SPI时序基本单元
3.1 起始条件 SS从高电平切换到低电平 3.2 终止条件 SS从低电平切换到高电平 3.3 交换一个字节模式0 CPOL0空闲状态时SCK为低电平 CPHA0SCK第一个边沿移入数据第二个边沿移出数据 3.4 交换一个字节模式1 CPOL0空闲状态时SCK为低电平 CPHA1SCK第一个边沿移出数据第二个边沿移入数据 3.5 交换一个字节模式2 CPOL1空闲状态时SCK为高电平 CPHA0SCK第一个边沿移入数据第二个边沿移出数据 3.6 交换一个字节模式3 CPOL1空闲状态时SCK为高电平 CPHA1SCK第一个边沿移出数据第二个边沿移入数据 4. 代码编写
4.1 引脚初始化
void MySPI_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA, GPIO_InitStructure); //将PA4、PA5和PA7引脚初始化为推挽输出GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA, GPIO_InitStructure); //将PA6引脚初始化为上拉输入/*设置默认电平*/MySPI_W_SS(1); //SS默认高电平MySPI_W_SCK(0); //SCK默认低电平
}
其中MySPI_W_SS(1); 和 MySPI_W_SCK(0);为封装函数可以参照下一条。
4.2 引脚置高低电平封装 为了后续代码的编写方便我们可以将初始化的引脚进行封装。
4.2.1 SPI写SS引脚电平 此函数需要用户实现内容当BitValue为0时需要置SS为低电平当BitValue为1时需要置SS为高电平。
void MySPI_W_SS(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue); //根据BitValue设置SS引脚的电平
}
4.2.2 SPI写SCK引脚电平 此函数需要用户实现内容当BitValue为0时需要置SCK为低电平当BitValue为1时需要置SCK为高电平。
void MySPI_W_SCK(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)BitValue); //根据BitValue设置SCK引脚的电平
}4.2.3 SPI写MOSI引脚电平 此函数需要用户实现内容当BitValue为0时需要置MOSI为低电平当BitValue非0时需要置MOSI为高电平。
void MySPI_W_MOSI(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)BitValue); //根据BitValue设置MOSI引脚的电平BitValue要实现非0即1的特性
}
4.2.4 I2C读MISO引脚电平 此函数需要用户实现内容当前MISO为低电平时返回0当前MISO为高电平时返回1。
uint8_t MySPI_R_MISO(void)
{return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6); //读取MISO电平并返回
}
也可以参考 STM32F1之I2C通信·软件I2C代码编写-CSDN博客 进行其他方法也能实现同样功能。
4.3 SPI起始 根据3.1我们可以看出SPI起始只需要将SS拉低就可以开始时序。
void MySPI_Start(void)
{MySPI_W_SS(0); //拉低SS开始时序
}
4.4 SPI终止 同理根据3.2我们可以看出SPI起始只需要将SS拉高就可以结束时序。
void MySPI_Stop(void)
{MySPI_W_SS(1); //拉高SS终止时序
}
4.5 SPI交换传输一个字节
4.5.1 模式0 这里需要注意一下在SPI中对于硬件SPI来说由于使用了硬件的移位寄存器电路所以下图中黄色部分几乎是同时发生的但是对于软件SPI来说程序执行需要一条一条执行有一个先后顺序因此我们可以将这里看成一个先后执行的逻辑 因此我们可以将其传送一位数据的流程如下先SS下降再移出数据在SCK上升沿在移入数据在SCK下降沿再移出数据。 uint8_t MySPI_SwapByte(uint8_t ByteSend)
{uint8_t ByteReceive 0x00; //定义接收的数据并赋初值0x00此处必须赋初值0x00后面会用到MySPI_W_MOSI(ByteSend 0x80); //使用掩码的方式取出ByteSend的指定一位数据并写入到MOSI线MySPI_W_SCK(1); //拉高SCK上升沿移出数据if (MySPI_R_MISO() 1){ByteReceive | 0x80;} //读取MISO数据并存储到Byte变量//当MISO为1时置变量指定位为1当MISO为0时不做处理指定位为默认的初值0MySPI_W_SCK(0); //拉低SCK下降沿移入数据MySPI_W_MOSI(ByteSend 0x40); //使用掩码的方式取出ByteSend的指定一位数据并写入到MOSI线MySPI_W_SCK(1); //拉高SCK上升沿移出数据if (MySPI_R_MISO() 1){ByteReceive | 0x40;} //读取MISO数据并存储到Byte变量//当MISO为1时置变量指定位为1当MISO为0时不做处理指定位为默认的初值0MySPI_W_SCK(0); MySPI_W_MOSI(ByteSend 0x20); //使用掩码的方式取出ByteSend的指定一位数据并写入到MOSI线MySPI_W_SCK(1); //拉高SCK上升沿移出数据if (MySPI_R_MISO() 1){ByteReceive | 0x20;} //读取MISO数据并存储到Byte变量//当MISO为1时置变量指定位为1当MISO为0时不做处理指定位为默认的初值0MySPI_W_SCK(0); MySPI_W_MOSI(ByteSend 0x10); //使用掩码的方式取出ByteSend的指定一位数据并写入到MOSI线MySPI_W_SCK(1); //拉高SCK上升沿移出数据if (MySPI_R_MISO() 1){ByteReceive | 0x10;} //读取MISO数据并存储到Byte变量//当MISO为1时置变量指定位为1当MISO为0时不做处理指定位为默认的初值0MySPI_W_SCK(0); MySPI_W_MOSI(ByteSend 0x08); //使用掩码的方式取出ByteSend的指定一位数据并写入到MOSI线MySPI_W_SCK(1); //拉高SCK上升沿移出数据if (MySPI_R_MISO() 1){ByteReceive | 0x08;} //读取MISO数据并存储到Byte变量//当MISO为1时置变量指定位为1当MISO为0时不做处理指定位为默认的初值0MySPI_W_SCK(0); //......一直移出到第八位return ByteReceive; //返回接收到的一个字节数据
} 以上代码太过冗余我们可以使用for循环来进行实现
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{uint8_t i, ByteReceive 0x00; //定义接收的数据并赋初值0x00此处必须赋初值0x00后面会用到for (i 0; i 8; i ) //循环8次依次交换每一位数据{MySPI_W_MOSI(ByteSend (0x80 i)); //使用掩码的方式取出ByteSend的指定一位数据并写入到MOSI线MySPI_W_SCK(1); //拉高SCK上升沿移出数据if (MySPI_R_MISO() 1){ByteReceive | (0x80 i);} //读取MISO数据并存储到Byte变量//当MISO为1时置变量指定位为1当MISO为0时不做处理指定位为默认的初值0MySPI_W_SCK(0); //拉低SCK下降沿移入数据}return ByteReceive; //返回接收到的一个字节数据
} 我们还可以根据“2.硬件电路”中的移位示意图中的数据进行操作编写代码
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{uint8_t i; for (i 0; i 8; i ) //循环8次依次交换每一位数据{MySPI_W_MOSI(ByteSend 0x80);ByteSend 1;MySPI_W_SCK(1); //拉高SCK上升沿移出数据if (MySPI_R_MISO() 1){ByteReceive | 0x01;}MySPI_W_SCK(0); //拉低SCK下降沿移入数据}return ByteReceive; //返回接收到的一个字节数据
} 这种方式相较于上一种代码效率更高但是原始数据ByteSend会发生改变因为这种方法是用移位数据本身进行操作的效率跟高但是原始数据ByteSend会在移位过程中发生改变对于上一种方式编写的代码是还有掩码一次提取数据每一位不会改变参数本身两种方法皆可使用。
4.5.2 模式1 我们也可以将其传送一位数据的流程描述如下先SS下降之后在SCK上升沿再移出数据在SCK下降沿在移入数据。
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{uint8_t i, ByteReceive 0x00; //定义接收的数据并赋初值0x00此处必须赋初值0x00后面会用到for (i 0; i 8; i ) //循环8次依次交换每一位数据{MySPI_W_SCK(1); MySPI_W_MOSI(ByteSend (0x80 i)); //使用掩码的方式取出ByteSend的指定一位数据并写入到MOSI线MySPI_W_SCK(0); if (MySPI_R_MISO() 1){ByteReceive | (0x80 i);} //读取MISO数据并存储到Byte变量//当MISO为1时置变量指定位为1当MISO为0时不做处理指定位为默认的初值0}return ByteReceive; //返回接收到的一个字节数据
}
4.5.2 模式2 可以对比模式0可以发现只是SCK极性相反只需要将模式0的代码中出现SCK的地方“1”改为“0”“0”改为“1”即可将极性翻转一下。注意初始化中的极性也要进行修改
4.5.2 模式3 同理可以对比模式1可以发现只是SCK极性相反只需要将模式0的代码中出现SCK的地方“1”改为“0”“0”改为“1”即可将极性翻转一下。注意初始化中的极性也要进行修改