|
爱科技、爱创意、爱折腾、爱极致,我们都是技术控
您需要 登录 才可以下载或查看,没有账号?立即注册
x
前几天写了SPI的程序,还是那样,用别人的改,记忆不深刻,今天基本又忘的差不多了
所以,又大体的看了一遍,又有些收获
SPI是串行总线的一种,有点类似232,但是232是靠双方频率同步通信,SPI是单方频率控制
SPI 一共有三根线,一根 MOSI,一根 SCK,一根 MISO
MOSI MOSI又称 SI,是 master output, slaver input(主出从入)的缩写
MISO 与MOSI相反,主入从出
SCK 时钟,也就是脉冲信号,就是高低电平变换
大概讲解一下,单片机是主器件,它提供频率变换时钟,被控制的芯片叫从器件,没有时钟,属于被动控制
相当于雇主拿个小皮鞭,cpu是雇主,从器件是奴隶,雇主拿皮鞭抽一下奴隶,相当于cpu给从器件一个时钟脉冲
奴隶被打叫了一声,相当于传递给雇主一个信号,这样,抽一下,叫一声,抽一下,叫一声,抽是MOSI发送的,叫是MISO接收的,他们是同步的
抽8下,叫8声,就完成一个字节的信息交换。 整个过程是双向的,就是我抽他就叫,写入信息同时必须得到信息
那么只写入,就把得到的信息丢掉就可以了,如果想得到信息,就得写入同样长度的没用的信息来换要读取的信息
大概就是这个原理
void SPIx_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable SPI1 and GPIOA clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //IO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); //SPI1总线时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //端口复用的时钟
/* Configure SPI1 pins: NSS, SCK, MISO and MOSI */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; //这3个IO就是硬件已经定义好的,找到就行,改不了的
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//SPI1 NSS
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //这个是片选信号,多个SPI器件时使用
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* SPI1 configuration */
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI1设置为两线全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI1为主模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行时钟在不操作时,时钟为高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //第二个时钟沿开始采样数据
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由软件(使用SSI位)管理
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //定义波特率预分频的值:波特率预分频值为8
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE); /* Enable SPI1 */ //使能SPI1外设
}
写入与读取库函数里的
static void SPI_Write_Byte(u8 byte)
{
//时序同发生字节一样,只是不返回读取的字节
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); /* Loop while DR register in not emplty */
SPI_I2S_SendData(SPI2, byte);/* Send byte through the SPI2 peripheral */
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); /* Wait to receive a byte */
SPI_I2S_ReceiveData(SPI2); /* Return the byte read from the SPI bus */
}
static u8 SPI_Read_Byte(void)
{
//等待发送信号寄存器为非空,然后发送一个字节到spi总线上
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI2, 0x00);
//等待接收信号寄存器为非空,然后从spi总线上接收一个字节
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); /* Wait to receive a byte */
return SPI_I2S_ReceiveData(SPI2);/* Return the byte read from the SPI bus */
}
用IO模拟SPI总线
for(i=8;i;i--)
{
SCK_OFF(); //时钟先拉低
if(value&0x80)MOSI_ON(); //从要发送的数据value高位开始,是1MOSI_ON,是0MOSI_OFF
else MOSI_OFF();
Delay(); //延时
value<<=1; //把要发送的数据左移一位为下次发送做准备
SCK_ON(); //时钟拉高,此时器件开始读取信号
T<<=1;
T|=MISO_IN; //把返回位读出来放最后一位
Delay();
}
SCK_OFF();
return;
} 循环8次,完成一字节交换
|
打赏
-
查看全部打赏
|