十二、SPI
1. IIC与SPI对比
1. IIC 是半双工通讯,无法同时收发信息;SPI 是全双工通讯,可以同时收发信息; 2. IIC 通讯协议较复杂,而 SPI 通讯协议较简单; 3. IIC 需要通过地址选择从机,而 SPI 只需一个引脚即可选中从机; 4. IIC 通讯速率一般为 100kHz 左右,而 SPI 可以达到 50MHz ; 5. IIC 需要的通讯线较少,而 SPI 需要较多。
2. SPI是什么?
SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线,并且 在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这 种简单易用的特性,越来越多的芯片集成了这种通信协议,比如 AT91RM9200 。
3. SPI物理架构
SPI 总线包含 4 条通讯线,分别为 SS、SCK、MOSI、MISO。它们的作用介绍如下 :
(1) MISO – Master Input Slave Output,主设备数据输入,从设备数据输出
(2) MOSI – Master Output Slave Input,主设备数据输出,从设备数据输入
(3) SCK – Serial Clock,时钟信号,由主设备产生
(4) CS – Chip Select,片选信号,由主设备控制
STM32F1 系列芯片有 3 个SPI 接口。
4. SPI工作原理
5. SPI工作模式
时钟极性(CPOL):
没有数据传输时时钟线的空闲状态电平
0:SCK在空闲状态保持低电平
1:SCK在空闲状态保持高电平
时钟相位(CPHA):
时钟线在第几个时钟边沿采样数据
0:SCK的第一(奇数)边沿进行数据位采样,数据在第一个时钟边沿被锁存
1:SCK的第二(偶数)边沿进行数据位采样,数据在第二个时钟边沿被锁存
模式 0 和模式 3 最常用。
模式 0 时序图:
模式 3 时序图:
6. SPI寄存器及库函数介绍
读取为w25q128 数据读出来
90—dum-00h
模块:W25Q128
小实验:读写W25Q128实验
实验目的
读写W25Q128
/---------w25q128.h--------------/
#include "sys.h"
//拉高拉低 读需要将nss拉低,之前虽然初始化了pin
//4引脚但是初始化是没有写但是直接write_pin比较麻烦实验在这里封装一次
#define W25Q128_CS(x) do{ x ? \ HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET): \ HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET); \ }while(0)uint16_t w25q128_read_id(void);
void w25q128_init(void);
/---------w25q128.c--------------/
spi接口封装
初始化
SPI_HandleTypeDef spi_handle = {0};//多个参数
void w25q128_spi_init(void)
{spi_handle.Instance = SPI1; //spi_handle.Init.Mode = SPI_MODE_MASTER; //选择是主设备还是从设备spi_handle.Init.Direction = SPI_DIRECTION_2LINES;//选择几根线的 既要读又要写--全双工spi_handle.Init.DataSize = SPI_DATASIZE_8BIT; //数据格式spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;// CPOL = 0 四种工作模式spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;// CPHA = 0 计数边沿 工作模式0spi_handle.Init.NSS = SPI_NSS_SOFT;// 随便拿一个GPIO口控制模块 spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;// 波特率分频随便选择一个spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;// 高位先行还是地位先行spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;// 暂时不用管spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;// CPOL = 0 spi_handle.Init.CRCPolynomial = 7;HAL_SPI_Init(&spi_handle);
}
msp函数
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{//gpio和中断,时钟进行操作 三个spi//首先先判断if(hspi->Instace == SPI1)
{GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_SPI1_SCK_ENABLE();//调用GPIO初始化函数gpio_initstruct.Pin = GPIO_PIN_4;gpio_initstruct.Mode= GPIO_MODE_OUTPUT;gpio_initstruct.Pull= GPIO_PULLUP;//上拉gpio_initstruct.Speed=GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,&gpio_initstruct);//CLK PA5 DI PA7gpio_initstruct.Pin = GPIO_PIN__5 | GPIO_PIN_7;gpio_initstruct.Mode = GPIO_MODE_AF_PP;HAL_GPIO_Init(GPIOA,&gpio_initstruct);//IN输入引脚gpio_initstruct.Pin = GPIO_PIN_6;gpio_initstruct.Mode = GPIO_MODE_INPUT;HAL_GPIO_Init(GPIOA,&gpio_initstruct);
}
}
封装读写函数 有个返回值
uint8_t w25q128_spi_swap_byte(uint8_t data)
{//发的同时也在收//句柄,发送的数据,接受的数据,发送几个字节,超时uint8_t recv_data = 0;HAL_SPI_TransmitReceive(&spi_handle,&data,&recv_data,1,1000);return recv_data;
}
w25q128初始化 调用spi初始化代码
void w25q128_init(void)
{w25q128_spi_init();
}
读id 引脚拉低写0
uint16_t w25q128_read_id(void)
{uint16_t device_id = 0;W25Q128_CS(0);//拉低w25q128_spi_swap_byte(0x90);//由数据手册可先发90w25q128_spi_swap_byte(0x00);//dummyw25q128_spi_swap_byte(0x00);w25q128_spi_swap_byte(0x00);device_id = w25q128_spi_swap_byte(0xFF) << 8;//两个字节的内容把这个数据放在device高位,左移8位device_id |= w25q128_spi_swap_byte(0xFF);//两个字节的内容把这个数据放在device低位为了不让高位干等会直接没掉,直接用|来操作}
写使能
void w25q128_writ_enable(void)
{}
读数据
16读的多的数据可能不够 写的内容 写的数据大小
void w25q128_read_data(uint32_t address, uint8_t *data, uint8_t size)
{}
页写 256字节最多
void w25q128_write_page(uint32_t address, uint8_t *data, uint8_t size)
{}
扇区擦除 位置传给他
void w25q128_erase_sector(uint32_t address)
{}
/------------main.c-----------/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "w25q128.h"
int main(void)
{HAL_Init(); /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */led_init(); /* LED初始化 */uart1_init(115200);w25q128_init();
// led1_on();
// led1_off();printf("helloworld!\r\n");uint16_t device_id =w25q128_read_id();printf("device_id: %X\r\n",device_id);while(1){ }
}