下面是重点研究的时序图:
1.SPI的IO口初始化2.SPI读取一个字节(MSB模式)3.SPI写入一个字节这3个函数都是看着时序图来编写:
跟着冲哥,慢慢来:
void SPI_Init(void) //初始化
{
CS = 1; //不选中该器件
MISO= 1; //
WP = 1;
MOSI= 1;
SCLK= 0; //spi模式0,sclk初始化为低电平
}
void SPI_WriteByte(u8 dat) //写入一个字节
{
u8 i;
for( i=0;i<8;i++ )
{
if( dat & 0x80 )
MOSI = 1;
else
MOSI = 0;
SCLK = 1; //下降沿
SCLK = 0;
dat <<=1;
}
}
u8 SPI_ReadByte(void) //读取一个字节
{
u8 i;
u8 dat=0;
for( i=0;i<8;i++ )
{
dat<<=1;
SCLK = 1;
if( MISO ) //从机往主机发送数据的引脚
dat |= 1;
// else
// dat |= 0;
SCLK = 0;
}
return dat;
}这是软件模拟的情况,能读出存储芯片的ID:
接着就换硬件的SPI:
先看寄存器:
首先是引脚选择,我们还是配成01 :P22 P23 P24 P25
串口1控制寄存器(SCON)我们要选择模式0,注意第四位REN必须配置为1才能接受数据。
硬件SPI 对应的3个函数:
void SPI_Init(void) //初始化
{
P_SW1 &= 0XF3; //1111 0011 P_SW1功能寄存器,引脚切换选择 B3B2位决定4种引脚配置
P_SW1 |= 0X04; //0000 0100 我们要选P22P23P24P25,先要把B3B2清零,才能改写为01
//清零用P_SW1 &= 1111 0011 B3B2改写为01:P_SW1 |= 0000 0100
SPCTL = 0X90; //SPI控制寄存器SPCTL,SPCTL是最核心的模式配置,第一位取1:忽略引脚功能,
//使用MSTR确定器件是主机还是从机,第二位是使能位,第三位DORD:SPI数据位发
//送/接收的顺序,0:先发送/接收数据的高位(MSB)1:先发送/接收数据的低
//位(LSB).第四位MSTR:器件主/从模式选择位:设置主机模式
//若 SSIG=0,则 SS 管脚必须为高电平且设置 MSTR 为1若 SSIG=1,则只需要设置
//MSTR 为 1(忽略 SS 管脚的电平)设置从机模式:
//若 SSIG=0,则 SS 管脚必须为低电平(与 MSTR 位无关)若 SSIG=1,则只需要设
//置 MSTR 为 0(忽略 SS 管脚的电平)第3位CPOL设置时钟极性和时钟相位控制
//CPOL:SPI 时钟极性控制,0:SCLK 空闲时为低电平,SCLK 的前时钟沿为上升沿,
//后时钟沿为下降沿1:SCLK 空闲时为高电平,SCLK 的前时钟沿为下降沿,后时钟沿
//为上升沿第2位CPHA:SPI 时钟相位控制,0:数据 SS 管脚为低电平驱动第一位数
//据并在 SCLK 的后时钟沿改变数据,前时钟沿采样数据(必须SSIG=0),1:数据在
//SCLK 的前时钟沿驱动,后时钟沿采样.最后1和0位是时钟频率选择
SPCTL |= 0X40; //只有1个存储芯片,配主从模式,第一位和第四位取1,先不使能,MSB方式读取:得
//0x90,配置完成,最后再使能SPI:SPCTL |= 0X40(第二位置1)
SCLK = 0; //时钟引脚初始化spi模式0,sclk初始化为低电平
SPIF = 1; //SPSTAT是状态寄存器,SPIF清空标志位要置1。当发送/接收完成 1 字节的数据后,
//硬件自动将此位置 1,并向 CPU 提出中断请求。当 SSIG 位被设置为0 时,由于
//SS管脚电平的变化而使得设备的主/从模式发生改变时,此标志位也会被硬件自动
//置1,以标志设备模式发生变化。注意:此标志位必须用户通过软件方式向此位写
//1 进行清零。SPIF不等于0,发送/接受就结束了,SPIF读到0表示正在读写,读到
//1表示完成
WCOL = 1; //WCOL:SPI写冲突标志位。当SPI在进行数据传输的过程中写SPDAT寄存器时,硬件
//将此位置1.注意:此标志位必须用户通过软件方式向此位写 1 进行清零。
//读取和写入完成之后都要清空SPIF和WCOL(置1)
}
void SPI_WriteByte(u8 dat) //写入一个字节
{
SPDAT = dat; //SPI 数据寄存器(SPDAT),SPI 发送/接收数据缓冲器。
while(SPIF == 0);
SPIF = 1; //每次读取写入完成后都要清空状态寄存器标志位
WCOL = 1; //每次读取写入完成后都要清空状态寄存器标志位
}
u8 SPI_ReadByte(void) //读取一个字节
{
SPDAT = 0XFF; //SPI 数据寄存器(SPDAT),SPI 发送/接收数据缓冲器。
//这里发送一个字节,主要是为了产生8位时钟脉冲,没有脉冲无法读数据
while(SPIF == 0);
SPIF = 1; //每次读取写入完成后都要清空状态寄存器标志位
WCOL = 1; //每次读取写入完成后都要清空状态寄存器标志位
return SPDAT;
}我已经注释的很详细了,方便以后查看..............
最后是USART_SPI
串口1同步模式控制寄存器1(USARTCR1)
这种串口配置,寄存器比较多,一开始容易晕菜:
不过,其实还好,有些我们不要管它..........
串口1同步SPI的函数如下:
void SPI_Init(void) //初始化USART_SPI寄存器
{
P_SW3 &= 0XF3; //1111 0011 引脚选择P_SW3 第3位第2位选01模式(对应引脚P22--P25)
P_SW3 |= 0X04; //0000 0100
SCON = 0x10; //串口1控制寄存器(SCON)模式0同步移位串行方式 REN位取1
USARTCR1=0x10; //串口1同步模式控制寄存器1(USARTCR1)DORD:SPI 模式数据位发送/接收的顺序
//0:先发送/接收数据的高位(MSB)
//1:先发送/接收数据的低位(LSB)
USARTCR4=0x00; //串口1同步模式控制寄存器4(USARTCR4),SPI 模式时钟选择,选最慢
USARTCR1|=0x08;//1:使能 SPI 功能
}
void SPI_WriteByte(u8 dat) //写入一个字节
{
TI = 0; //清标志位
SBUF = dat;
while(!TI);
}
u8 SPI_ReadByte(void) //读取一个字节
{
TI = 0; //清标志位
SBUF = 0X00; //产生8个时钟脉冲信号用来传递数据
while(!TI);
return SBUF;
} 也是尽可能详细的注释,方便以后查询.....................
运行结果也很顺利 ,感觉真的是好像七窍通了六窍,不是真的懂了,只是做了一遍,嘻嘻!好了,今天就这样啦!
今天我们继续学习 第二十九集:SPI读写FLASH芯片
先看看大致任务:
1.W25X40CL简介
2.数据读写
3.代码实现
4.实战小练(温室大棚历史温度记录装置)
看手册,还是要英文好,所以我们当初开日语的,很吃亏!
命名规则如下:
我在咱们的试验箱上没有找到这颗芯片,不过我们有替代品:
GD AY2122 25Q40CTIGUFT369
试验箱说明书的图纸:
对应型号是:Ul1PM25LV040 都是一样的使用方法