STM32的SPI学习(SPI芯片为SST25VF016B)
来源:互联网 发布:淘宝网抢红包 编辑:程序博客网 时间:2024/06/05 10:54
学习板芯片为STM32F103VE
先简单介绍下SPI(全称:Serial Peripheral interface,串行外围设备接口):SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,是一种高速的,全双工,同步的通信总线。一般SPI芯片与MCU通信,只会使用4个管脚:MOSI(主输出),MISO(主输入),CS(片选低电平有效),SCK(时钟)
STM32内的SPI的特点:
1 8或16位传输帧格式选择
2 可编程的时钟极性(CPOL)和相位(CPHA)
3 可编程的数据顺序,MSB在前或LSB在前
4 8个主模式波特率预分频系数(最大为fPCLK/2)
5 支持DMA功能的1字节发送和接收缓冲器:产生发送和接受请求
6 可触发中断的专用发送和接收标志
SPI较重要的寄存器:
8或16位传输帧格式选择 由SPI_CR1寄存器上的DFF位确定,0:8位
时钟极性和相位由SPI_CR1寄存器上的CPOL,CPHA 位确定
模式0:CPOL=0,CPHA=0:SCK在空闲时保持低电平,在第一个变化沿传递数据 (本次使用的SPI芯片SST25VF016B只能使用在模式0和3)
模式1:CPOL=0,CPHA=1:SCK在空闲时保持低电平,在第二个变化沿传递数据
模式2:CPOL=1,CPHA=0:SCK在空闲时保持高电平,在第一个变化沿传递数据
模式3:CPOL=1,CPHA=1:SCK在空闲时保持高电平,在第二个变化沿传递数据
可编程的数据顺序 ,MSB在前或LSB在前 由SPI_CR1寄存器中的LSBFIRST位确定,0:MSB在前
8个主模式波特率预分频系数(最大为fPCLK/2) 由SPI_CR1寄存器上的BR[2:0]确定
应用程序通过3个状态标志可以完全监控SPI总线的状态:
1.发送缓冲器空闲标志(TXE),此标志为’1’时表明发送缓冲器为空,要等到该位为0,进行下一次发送
2.接收缓冲器非空(RXNE),同理
3.忙(Busy)标志
SPI芯片SST25VF016B
8个管脚,一般只有4个管脚与MCU连接,SI,SO,CE,SCK
状态寄存器:
更多信息参考SST25VF016B数据手册
STM32y与SST25VF016B进行SPI通信代码实现:
//时钟配置RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//用于打印读取到的数据RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
//管脚配置 SPI PA5:SCK PA6:MOSI PA7:MISO PE6:CSGPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOE,&GPIO_InitStructure);GPIO_SetBits(GPIOE,GPIO_Pin_6);
//SPI配置SPI_InitTypeDef SPI_InitStructure;SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;//双向全双工SPI_InitStructure.SPI_Mode=SPI_Mode_Master; //主机模式SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b; //每次发生8位SPI_InitStructure.SPI_CPOL=SPI_CPOL_High; //时钟空闲时为高SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge; //第2个变化沿传递数据 模式3SPI_InitStructure.SPI_NSS=SPI_NSS_Soft; //NSS软件模式SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_8;//时钟8分频 SPI 在APB2上,则为9MSPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB; //高位在前SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI1,&SPI_InitStructure);SPI_Cmd(SPI1,ENABLE); //SPI发送数据u8 SPI_SendData(u8 data){ while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET); SPI_I2S_SendData(SPI1,data);}//SPI接收数据 u8 SPI_ReadData(void){ while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)==RESET); SPI_I2S_SendData(SPI1, 0); while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)==RESET); return SPI_I2S_ReceiveData(SPI1);}//根据芯片SST25VF016B的数据手册,编写对该芯片操作的函数//读取状态寄存器u8 RDSR(void){ u8 data; SPI_CS_L; SPI_SendData(0x05); data = SPI_ReadData(); SPI_CS_H; return data;}//根据状态寄存器最低位BUSY判断芯片是否处于忙状态u8 Is_Busy(void){ if((RDSR()&0x01)==1) return 1; //1 : 忙 else return 0; //0 :空闲}void SST_SPI_Read(u32 addr,u8* buf,u16 size){ int i =0; SPI_CS_L; SPI_SendData(0x0B); SPI_SendData((addr&0xFFFFFF)>>16); //È¡24λµÄ¸ß8λ SPI_SendData((addr&0xFFFF)>>8); //È¡24λµÄÖÐ8λ SPI_SendData(addr&0xFF); //È¡24λµÄµÍ8λ SPI_SendData(0); while(i<size){ buf[i] = SPI_ReadData(); i++; } SPI_CS_H;}//void SST_SPI_WRITE(u32 addr,u8* buf,u16 size){ int i; SST_SPI_DEL4K(addr); //先清除要写的地址原先的数据 WRSR(); //使能写状态寄存器,打开写保护 WREN(); //使能写数据存储器 /*必须要先擦除目标地址的数据,再使能写状态寄存器,打开写保护 再使能写数据存储器,顺序不可调换*/ SPI_CS_L; SPI_SendData(0xAD); SPI_SendData((addr&0xFFFFFF)>>16); //先发送地址高8位 SPI_SendData((addr&0xFFFF)>>8); //发送地址中8位 SPI_SendData(addr&0xFF); //发送地址低8位 因为该芯片是一共24位 SPI_SendData(buf[0]); SPI_SendData(buf[1]); SPI_CS_H; i=2; while(i<size){ delay_us(10); SPI_CS_L; SPI_SendData(0xAD); SPI_SendData(buf[i++]); SPI_SendData(buf[i++]); SPI_CS_H; } delay_us(10); WRDI(); // while(Is_Busy());}//4KB擦除void SST_SPI_DEL4K(u32 addr){WRSR(); //使能写状态寄存器,打开写保护 WREN(); //使能写数据存储器/*上面2个函数的调用顺序不能调换*/
SPI_CS_L;
SPI_SendData(0x20);
SPI_SendData((addr&0xFFFFFF)>>16);
SPI_SendData((addr&0xFFFF)>>8);
SPI_SendData(addr&0xFF);
SPI_CS_H;
while(Is_Busy());
}
//写数据存储器使能
void WREN(void){
SPI_CS_L;
SPI_SendData(0x06);
SPI_CS_H;
}
//写数据存储器禁止
void WRDI(void){
SPI_CS_L;
SPI_SendData(0x04);
SPI_CS_H;
while(Is_Busy());
}
//使能写状态寄存器,打开写保护
void WRSR(void){
SPI_CS_L;
SPI_SendData(0x50);
SPI_CS_H;
SPI_CS_L;
SPI_SendData(0x01); // BP3 BP2 BP1 BP0 置0,取消写保护
SPI_SendData(0);
SPI_CS_H;
while(Is_Busy());
}
//读取器件ID,用于判断SPI通信是否成功
u16 RDID(void){
u16 id;
SPI_CS_L;
SPI_SendData(0x90);
SPI_SendData(0x00);
SPI_SendData(0x00);
SPI_SendData(0x00);
id = SPI_ReadData();
id<<=8;
id += SPI_ReadData();
SPI_CS_H;
return id;
}
//主函数
int main(void){
u8 readBuf[100];
u8 str[]="hello world 你好";
u16 size=sizeof(str)/sizeof(str[0]);
RCC_Configuration();
GPIO_Configuration();
USART_Configuration();
SPI_Configuration();
/*data = RDID();
printf("%X\r\n",data);*/
SST_SPI_WRITE(0,str,size); //写入hello world 你好
delay_ms(100);
SST_SPI_Read(0,readBuf,size);//读出hello world 你好
printf("%s\r\n",readBuf);
delay_ms(5000);
while(1){
}
}
- STM32的SPI学习(SPI芯片为SST25VF016B)
- STM32的SPI学习笔记
- SPI实现SST25VF016B驱动(Flash)
- 芯片的SPI口
- STM32 SPI学习笔记!
- STM32 SPI 学习笔记
- stm32 SPI学习
- stm32的spi
- STM32的SPI时钟
- stm32的SPI总结
- stm32 华邦W25X32芯片spi总线配置
- STM32-SPI实验学习笔记
- STM32 SPI
- STM32 SPI
- STM32之SPI的思考
- STM32 SPI DMA 的使用
- STM32---SPI 的CPOL、CPHA
- STM32之SPI的使用
- 第三周LeetCode算法题两道
- 51单片机八路抢答器proteus仿真
- Hibernate5:Hibernate框架下的基于注解配置的多表关联的入门级例子(完整版)
- RabbitMQ集群及负载均衡搭建
- 括号运算符重载
- STM32的SPI学习(SPI芯片为SST25VF016B)
- MD5加密算法实现
- webpack manifest.js分割的一个错误
- 15算法课程 14. Longest Common Prefix
- 逻辑与和逻辑或的重载
- 1.Redis简介
- jedis连接池无法写入/读取数据的问题
- 2PC,Raft和Paxos笔记
- 继承的概念