做网站要写多少行代码,100款不良网站进入窗口软件,wordpress单题问卷,网络营销策略实施的步骤目录
一:SPL通信
1:简历
2:硬件电路
3:移动数据图
4:SPI时序基本单元
A : 开/ 终条件
B:SPI时序基本单元
A:模式0
B:模式1
C:模式2
D:模式3
C:SPl时序
A:发送指令
B: 指定地址写
C:指定地址读
5#xff1a;NSS(CS)
6#xff1a;时钟
二: W25Q64
1:简历
2…
目录
一:SPL通信
1:简历
2:硬件电路
3:移动数据图
4:SPI时序基本单元
A : 开/ 终条件
B:SPI时序基本单元
A:模式0
B:模式1
C:模式2
D:模式3
C:SPl时序
A:发送指令
B: 指定地址写
C:指定地址读
5NSS(CS)
6时钟
二: W25Q64
1:简历
2: 硬件电路
3:W25Q64框图
4: Flash操作注意事项
5:指令集
三:HAL
A:宏函数
B:轮询方式
C:中断
C:DMA
四案例
A轮询方式--W25Q64
B:单线双向模式--MAX7219数码管
C中断方式--W25Q64
D:MDA----W25Q64
主从通信
A:中断主机身份不改变
B:中断DMA
C多主机通信--主从身份可以改变 一:SPL通信
STM32F1c8T6 有2个SPI。
1:简历 SPISerial Peripheral Interface是由Motorola公司开发的一种通用数据总线 四根通信线SCKSerial Clock、MOSIMaster Output Slave Input、MISOMaster Input Slave Output、SSSlave Select(NSS) 同步(有时钟线)全双工 (传输线有2条,发送和接受线路) 支持总线挂载多设备一主多从 SPl没有应答机制 2:硬件电路 所有SPI设备的SCK、MOSI、MISO分别连在一起 主机另外引出多条SS(NSS)控制线分别接到各从机的SS(NSS)引脚 输出引脚配置为推挽输出输入引脚配置为浮空或上拉输入 SS(NSS)也叫CS片选信号 : 和全部的从机连接, 用于选择主机和那个从机进行通信, 低电平有效; 每个从机的SS(CS)都和主机的SSX相互连接, SS对于主机来说的话,就是输出信号, 从机的话就是输入信号 IO的配置 : 都是以STM32为主角进行的. 主机输出信号配置---推挽输出, 主机输入信号配置----浮空或上拉输入 SCK : 时钟线, 时钟线完全由主机掌控, 所以对于主机来说时钟线为输出; 对于所有从机来说时钟线都为输入; 这样主机的同步时钟就能送到各个从机了 MOSI : 主机输出,从机输入 MISO : 主机输入,从机输出 关于CS和MISO主机输入,从机输出 : 当从机没有被选中的时候,也就是SS段电平为1; 从机的MISO主机输入,从机输出必须切换为高阻态 , 高阻态就相当于引脚断开不输出任何电平; 这样就可以防止一条线有多个输出而导致的电平冲突的问题了; 在SS为低电平时MISO才允许变为推挽输出----从机的操作-------一般情况下我们只需要写主机的程序,从机的程序不需要我们操心 3:移动数据图
交换数据, 高位先行 SPI的数据收发都是基于字节交换这个基本单元来进行的 (移位模型) 首先我们规定波特率发生器时钟的上升沿主机和从机都移出数据; 下将沿移入数据; 数据为从左往右运动,所以是高为先行, 首先波特率发生器时钟产生上生沿, 主机把它的最高位的数据放在MOSI上面, 从机把它最高位置的数据放在MISO上面; 在由特率发生器产生的下降沿移入数据; 在MISO数据线上从机的最高位的数据放在主机的最低位置上面; MOSI上面主机最高位的数据放在从机的最低位置 4:SPI时序基本单元
A : 开/ 终条件 起始条件SS从高电平切换到低电平 终止条件SS从低电平切换到高电平 B:SPI时序基本单元
在任何操作下, 我们只管主机(只写主机的代码) , 从机它自动操作(不用写从机的代码)
我们经常使用的是模式0主机和从机的模式必须一样主机采用什么模式取决于操作的芯片支持那种工作模式。 A:模式0 交换一个字节模式0 CPOL0空闲状态时SCK为低电平 CPHA0SCK第一个边沿移入数据第二个边沿移出数据第一个边沿采集 SCL上升沿主机和从机同步移入数据; SCL下降沿主机和从机同步移出数据
/**
* brief SPL交换数据--使用的为模式0DIMOSI----SPI主机输出从机输入DOMISO)-------SPI主机输入从机输出我们只操作主机:首先主机移出最高位,放在MOSI上面,---主机操作需要我们来齐次从机把数据放在MISO上面----从机的操作不需要我们管* param ByteSend: 主机给从机发送的数据* retval 主机读取的数据----即从机给主机发送的数据*/
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{ MySPI_W_SCK(0);//一般来说是用来清零的;
//一般来说|是用来值一的;uint8_t ByteReceive0x00;for (uint8_t i0;i8;i){MySPI_W_MOSI(ByteSend (0x80i)); //MOSI主机输出数据 1000 0000 /*我们只操作主机: SCL上升沿主机和从机同步移入数据, 从机会自动把主机给它的最高为移动到了从机里面---从机不需要我们操作主机操作 : 主机需要把从机给它发送的数据移动到了主机里面---即读取MISO线上的数据*/MySPI_W_SCK(1);if (MySPI_R_MISO() 1){ByteReceive | (0x80 i);}//MySPI_R_MISO主机读取数据MySPI_W_SCK(0);//SCL下降沿主机和从机同步移出数据//|---置1}return ByteReceive;
} 在任何操作下, 我们只管主机(只写主机的代码) , 从机它自动操作(不用写从机的代码) B:模式1 交换一个字节模式1 CPOL0空闲状态时SCK为低电平 CPHA1SCK第一个边沿移出数据第二个边沿移入数据第二个边沿采集 SPl为了可以配置更多的时钟芯片, 给我们了2个可以自己调节的位, 分别为:CPOL (Clock Polarity)时钟极性和CPHA (Clock Phase)时钟相位配置这两个为, 就构成了4种模式 模式1 : 波特率发生器时钟的上升沿主机和从机都移出数据; 下将沿移入数据; 模式1的数据移动方式和 3:移动数据图 一样 , 详情参考----3:移动数据图 C:模式2 交换一个字节模式2 CPOL1空闲状态时SCK为高电平 CPHA0SCK第一个边沿移入数据第二个边沿移出数据 第一个边沿采集。同样是在SCLK下降沿进行数据采样上升沿进行数据传输。 D:模式3 交换一个字节模式3 CPOL1空闲状态时SCK为高电平 CPHA1SCK第一个边沿移出数据第二个边沿移入数据第二个边沿采集。在SCLK上升沿进行数据采样下降沿进行数据传输。 C:SPl时序
A:发送指令
规定 : SPL起始的第一个字节为指令集
发送指令
向SS指定的设备发送指令0x06--0x06使能 B: 指定地址写 指定地址写 向SS指定的设备发送写指令0x02)---0x02写入的指令集 随后在指定地址Address[23:0]下写入指定数据Data) SPl没有应答机制, 交换一个字节后, 直接开始交换下一个字节 C:指定地址读 指定地址读 向SS指定的设备发送读指令0x03---0x03发送指令的指令集 随后在指定地址Address[23:0]下读取从机数据Data 5NSS(CS) SPI_NSS_SOFT 应用STM32在做主机防止丢失主机身份。SPI支持多主机通信一个STM32可以在主机和从机身份中来回切换。 SPI_NSS_HARD_INPUT:
主模式切换为从模式
主控从主机切换为从机身份。NSS被拉意外丢失主模式。
应用多少应用于多主机身份。 SPI_NSS_HARD_OUTPUT: 6时钟 SPI1挂载在APB2总线上APB2总线的最大时钟频率为72MHZ
SPI2挂载在APB1总线上APB2总线的最大时钟频率为36MHZ
二: W25Q64
1:简历 W25Qxx系列是一种低成本、小型化、使用简单的非易失性存储器常应用于数据存储、字库存储、固件程序存储等场景。支持模式0和模式3。 存储介质Nor Flash闪存 时钟频率80MHz / 160MHz (Dual SPI) / 320MHz (Quad SPI) 存储容量24位地址 W25Q40 4Mbit / 512KByte W25Q80 8Mbit / 1MByte W25Q16 16Mbit / 2MByte W25Q32 32Mbit / 4MByte W25Q64 64Mbit / 8MByte W25Q128 128Mbit / 16MByte W25Q256 256Mbit / 32MByte 2: 硬件电路 3:W25Q64框图 4: Flash操作注意事项
非易失性存储器---掉电不丢失
写入操作时 写入操作前必须先进行写使能------------是一种保护措施防止你误操作的 每个数据位只能由1改写为0不能由0改写为1写入只能写0不能写1。--------------Flash并没有像RAM那样的, 直接完全覆盖改写的能力. eg:在某一个直接的储存单元首先储存了0xaa 1010 1010 在储存0x55 0101 0101 因为Flash没有直接覆盖数据的能力, 在加上第二条规定的限制实际储存的数据为: 0000 0000 不是0x55, 使用在写入第二给数据前必须擦除之前的数据 写入数据前必须先擦除擦除后所有数据位变为1--------------有专门的擦除电路把之前写的数据都值1(0xFF), 就可以弥补第二条规定的不足 擦除必须按最小擦除单元进行------------不能指定某一个字节去擦除, 要擦就得一大片一起擦, 在我们这个芯片里; 你可以选择整个芯片擦除, 也可以选择按块擦除或者按扇区擦除; 最小的擦除单元就是一个扇区, 个扇区是4KB就是4096个字节 连续写入多字节时最多写入一页的数据超过页尾位置的数据会回到页首覆盖写入--------一个写入时序最多只能写一页的数据也就是256字节; 一个页缓存区它只有256字节; Flash的写入太慢了. 跟不上SPI的频率. 所以写入的数据会先放在RAM里暂存. 必须得从页起始位置开始才能最大写入256字节, 如果从页中间的地址开始写, 那写到页尾时这个地址就会跳回到页首, 这会导致地址错乱 写入操作结束后芯片进入忙状态不响应新的读写操作--------要想知道芯片什么时候结束忙状态了, 我们可以使用读取状态寄存器的指令, 看一下状态寄存器的BUSY位是否为1, BUSY位为0时芯片就不忙了我们再进行操作 在发出擦除指令后芯片也会进入忙状态, 我们也得等待忙状态结束后才能进行后续操作 扇区擦除也是写入所以需要使能
读取操作时 直接调用读取时序无需使能无需额外操作没有页的限制 读取操作结束后不会进入忙状态但不能在忙状态时读取, 5:指令集
INSTRUCTION NAME---指令的名字; BYTE----字节X Write Enable----写使能指令集 Write Disable --------写失能指令集 Read Status Register-1---------读状态寄存器1--作用: 判断寄存器在不在忙, 具体见 二: 4 Page Program----------页编程, 写数据,max为256个字节 Sector Erase (4KB)-------------按4KB的扇区擦除 JEDEC ID----------读取ID Read Data-----读取数据 三:HAL
A:宏函数 B:轮询方式 HAL_SPl_Transmit: HAL_SPl_Receive: C:中断 C:DMA 四案例
A轮询方式--W25Q64 #include stm32f1xx_hal.h
#include rcc.h
#include led.h
#include delay.h
#include UART.h
#include stdarg.h
#include stdio.h
#include key.h
#include SPI.h
#include w25q64.huint8_t wbuff[4096];
uint8_t rbuff[4096];
uint16_t i0;int main(void)
{HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */LED_Init(); /* LED初始化 */Uart_Init(115200);LED_Exit_Init();KEY_Init();Spi1_Init();W25q64_SectorErase(0);W25q64_ReadID();//
// for(i0;i4096;i)
// {
// wbuff[i]0x66;
//
// }
//
// for(i0;i16;i)
// {
// //W25q64_WritePage(wbuff[i*256],i);
// }
//
// W25q64_ReadData(rbuff,0,4096);
//
// for(i0;i4096;i)
// {
// printf(rbuff[%d]%x\r\n,i,rbuff[i]);
// }while (1){}
}#include stm32f1xx_hal.hSPI_HandleTypeDef SPI_Handle;void Spi1_Init()
{SPI_Handle.InstanceSPI1;//SPI1挂载在APB2总线上APB2总线72MHZSPI_Handle.Init.BaudRatePrescalerSPI_BAUDRATEPRESCALER_2; //分频SPI_Handle.Init.CLKPhaseSPI_PHASE_1EDGE; //第一个边沿捕获CPHASPI_Handle.Init.CLKPolaritySPI_POLARITY_LOW; //CPOL时钟极性SPI_Handle.Init.CRCCalculationSPI_CRCCALCULATION_DISABLE; //是否开启CRC校验硬件自动校验主要看操作的从机使用否支持CRC校验SPI_Handle.Init.DataSizeSPI_DATASIZE_8BIT;SPI_Handle.Init.DirectionSPI_DIRECTION_2LINES; //双线全双工SPI_Handle.Init.FirstBitSPI_FIRSTBIT_MSB; //高位先行SPI_Handle.Init.TIModeSPI_TIMODE_DISABLE; //不支持TI模式SPI_Handle.Init.ModeSPI_MODE_MASTER; //主机模式SPI_Handle.Init.NSSSPI_NSS_SOFT; //NSS软件模式HAL_SPI_Init(SPI_Handle);
}void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI1){__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_SPI1_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitType;GPIO_InitType.ModeGPIO_MODE_OUTPUT_PP; //推挽输出 普通的IO口GPIO_InitType.PinGPIO_PIN_0;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA,GPIO_InitType); GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用推挽输出 复用为SPIGPIO_InitType.PinGPIO_PIN_5;GPIO_InitType.SpeedGPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,GPIO_InitType); //MISO 主机输入,从机输出GPIO_InitType.ModeGPIO_MODE_AF_INPUT; //复用输入 复用为SPIGPIO_InitType.PinGPIO_PIN_6;GPIO_InitType.PullGPIO_NOPULL;HAL_GPIO_Init(GPIOA,GPIO_InitType); //MOSI 主机输出,从机输入GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用推挽输出 复用为SPIGPIO_InitType.PinGPIO_PIN_7;GPIO_InitType.SpeedGPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,GPIO_InitType); }}
#include stm32f1xx_hal.h
#include stdarg.h
#include stdio.h
#include SPI.h
#include stdarg.h
#include stdio.h
#include UART.h
#define CS_ENABLE HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
#define CS_DISABLE HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);/*** brief 查看busy位是否忙碌.*/
void W25q64_Busy(void)
{ uint8_t cmd[2],data[2];cmd[0]0x05;cmd[1]0xFF;do{CS_ENABLE;HAL_SPI_TransmitReceive(SPI_Handle,cmd,data,2,1000);CS_DISABLE;}while((data[1] 0x01)0x01); //busy为0不忙}
/*** brief 写使能.*/
void W25q64_WriteEnable(void)
{uint8_t cmd;cmd0x06;W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,1,1000);CS_DISABLE;
}/*** brief 擦除一个扇区的数据4K;4*10244096* param 擦除第几页的数据 */
void W25q64_SectorErase(uint32_t Sectornum)
{uint8_t cmd[4];cmd[0]0x20;cmd[1](Sectornum*4096)16;cmd[2](Sectornum*4096)8;cmd[3](Sectornum*4096)0;W25q64_WriteEnable();W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,4,1000);CS_DISABLE;
}/*** brief 写入一页数据一页256字节* param data: 写入的数据* param PageNum给第几页写入数据*/
void W25q64_WritePage(uint8_t * data,uint32_t PageNum)
{uint8_t cmd[4];cmd[0]0x02;cmd[1](PageNum*256)16;cmd[2](PageNum*256)8;cmd[3](PageNum*256)0;W25q64_WriteEnable();W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,4,1000);HAL_SPI_Transmit(SPI_Handle,data,256,5000); //sizeof(data)CS_DISABLE;
}/*** brief 读取数据* param *rdata 读取数据存放的地址* param addr 读取第几页* param len 读取数据的长度几个字节* retval */
void W25q64_ReadData(uint8_t *rdata,uint32_t addr ,uint32_t len)
{uint8_t cmd[4];cmd[0]0x03;cmd[1]addr16;cmd[2]addr8;cmd[3]addr0;W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,4,1000);HAL_SPI_Receive(SPI_Handle,rdata,len,50000);CS_DISABLE;}/*** brief 读取ID.*/
void W25q64_ReadID()
{uint8_t cmd[1],data_id[3];cmd[0]0x9F;W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,1,1000);HAL_SPI_Receive(SPI_Handle,data_id,sizeof(data_id),50000);CS_DISABLE;printf(W25q64的ID为制造商ID%02X 设备ID%02X 容量ID%02X\r\n, data_id[0], data_id[1], data_id[2]); } 重要参数
HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)typedef struct
{ uint32_t Mode; ! 指定SPI的工作模式。 这个参数可以是ref SPI_Mode中的一个值 */ uint32_t Direction; ! 指定SPI双向模式的状态。 这个参数可以是ref SPI_Direction中的一个值 */ uint32_t DataSize; ! 指定SPI的数据大小。 这个参数可以是ref SPI_Data_Size中的一个值 */ uint32_t CLKPolarity; ! 指定串行时钟的稳定状态。 这个参数可以是ref SPI_Clock_Polarity中的一个值 */ uint32_t CLKPhase; ! 指定用于位捕获的时钟活动边沿。 这个参数可以是ref SPI_Clock_Phase中的一个值 */ uint32_t NSS; ! 指定NSS信号是由硬件NSS引脚管理还是由软件使用SSI位管理。 这个参数可以是ref SPI_Slave_Select_management中的一个值 */ uint32_t BaudRatePrescaler; ! 指定波特率预分频值用于配置发送和接收SCK时钟。 这个参数可以是ref SPI_BaudRate_Prescaler中的一个值 note 通信时钟是从主时钟派生出来的。从机时钟不需要设置。 */ uint32_t FirstBit; ! 指定数据传输是从MSB最高有效位还是LSB最低有效位开始。 这个参数可以是ref SPI_MSB_LSB_transmission中的一个值 */ uint32_t TIMode; ! 指定是否启用TI模式。 这个参数可以是ref SPI_TI_mode中的一个值 */ uint32_t CRCCalculation; ! 指定是否启用CRC循环冗余校验计算。 这个参数可以是ref SPI_CRC_Calculation中的一个值 */ uint32_t CRCPolynomial; ! 指定用于CRC计算的多项式。 这个参数必须是一个介于Min_Data 1和Max_Data 65535之间的奇数 */
} SPI_InitTypeDef; B:单线双向模式--MAX7219数码管 频率 模式 CLK极性默认为低上升沿采集数据说明第一个边沿采集数据。 高位先行 译码的方法
#include stm32f1xx_hal.h
#include rcc.h
#include led.h
#include delay.h
#include UART.h
#include stdarg.h
#include stdio.h
#include key.h
#include SPI.h
#include MAX7219.hint main(void)
{HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */LED_Init(); /* LED初始化 */Uart_Init(115200);LED_Exit_Init();KEY_Init();Spi2_Init();delay_ms(50);Init_MAX7219();delay_ms(1000);Write_Max7219(0x0f, 0x00); //显示测试1测试结束正常显示0Write_Max7219(1,8); //第一个数码管显示1//Write_Max7219(1,0x88); //D7位变为高电平控制小数点Write_Max7219(2,7);Write_Max7219(3,6);Write_Max7219(4,5); Write_Max7219(5,4);Write_Max7219(6,3);Write_Max7219(7,2);Write_Max7219(8,1); while (1){}
}#include stm32f1xx_hal.hSPI_HandleTypeDef SPI2_Handle;//MAX7219
void Spi2_Init()
{SPI2_Handle.InstanceSPI2;//SPI2挂载在APB1总线上APB2总线36MHZSPI2_Handle.Init.BaudRatePrescalerSPI_BAUDRATEPRESCALER_16; //分频 36/162SPI2_Handle.Init.CLKPhaseSPI_PHASE_1EDGE; //第一个边沿捕获CPHASPI2_Handle.Init.CLKPolaritySPI_POLARITY_LOW; //CPOL时钟极性 SPI_POLARITY_HIGHSPI2_Handle.Init.CRCCalculationSPI_CRCCALCULATION_DISABLE; //是否开启CRC校验硬件自动校验主要看操作的从机使用否支持CRC校验SPI2_Handle.Init.DataSizeSPI_DATASIZE_8BIT;SPI2_Handle.Init.DirectionSPI_DIRECTION_2LINES; //单线半双工SPI2_Handle.Init.FirstBitSPI_FIRSTBIT_MSB; //高位先行SPI2_Handle.Init.TIModeSPI_TIMODE_DISABLE; //不支持TI模式SPI2_Handle.Init.ModeSPI_MODE_MASTER; //主机模式SPI2_Handle.Init.NSSSPI_NSS_SOFT; //NSS软件模式HAL_SPI_Init(SPI2_Handle);
}void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI2){__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_SPI2_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitType;//片选GPIO_InitType.ModeGPIO_MODE_OUTPUT_PP; //推挽输出 普通的IO口GPIO_InitType.PinGPIO_PIN_12;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB,GPIO_InitType); GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用推挽输出 复用为SPIGPIO_InitType.PinGPIO_PIN_13;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB,GPIO_InitType); //MISO 主机输入,从机输出GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用输入 复用为SPIGPIO_InitType.PinGPIO_PIN_15;GPIO_InitType.PullGPIO_NOPULL;HAL_GPIO_Init(GPIOB,GPIO_InitType); }}#include stm32f1xx_hal.h
#include stdarg.h
#include stdio.h
#include SPI.h
#include UART.h
#include delay.h
/* address define */
#define NO_OP 0x00
#define DIGIT0 0x01
#define DIGIT1 0x02
#define DIGIT2 0x03
#define DIGIT3 0x04
#define DIGIT4 0x05
#define DIGIT5 0x06
#define DIGIT6 0x07
#define DIGIT7 0x08
#define DECODE_MODE 0x09 //译码控制寄存器
#define INTENSITY 0x0A // 亮度控制寄存器
#define SCAN_LIMIT 0x0B //扫描界限寄存器
#define SHUT_DOWN 0x0C //关断模式寄存器
#define DISPLAY_TEST 0x0F //显示测试寄存器
/* mode define */
#define NORMAL_MODE 0
#define NO_DECODE_D0_D7 0x00
#define DECODE_D0_ONLY 0x01
#define DECODE_D0_D3_ONLY 0x0F
#define DECODE_D0_D7 0xFF#define CS_ENABLE_MAX7291 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
#define CS_DISABLE_MAX7291 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET); //功能向MAX7219内部寄存器写入数据
//参数addr、dat
void Write_Max7219(uint8_t addr,uint8_t dat)
{CS_ENABLE_MAX7291; HAL_SPI_Transmit(SPI2_Handle,addr,1,1000); //写入地址 delay_us(10);//必须点阵不显示时可以延长此延时调试HAL_SPI_Transmit(SPI2_Handle,dat,1,1000); //写入地址 delay_us(10);//必须点阵不显示时可以延长此延时调试CS_DISABLE_MAX7291;
}//MAX7291初始化
void Init_MAX7219(void)
{Write_Max7219(0x09, 0xFF); //译码方式不译码Write_Max7219(0x0a, 0x03); //亮度Write_Max7219(0x0b, 0x07); //扫描界限4个数码管显示Write_Max7219(0x0c, 0x01); //掉电模式0普通模式1Write_Max7219(0x0f, 0x01); //显示测试1测试结束正常显示0
} 不译码的方法
#include stm32f1xx_hal.h
#include rcc.h
#include led.h
#include delay.h
#include UART.h
#include stdarg.h
#include stdio.h
#include key.h
#include SPI.h
#include MAX7219.hint main(void)
{HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */LED_Init(); /* LED初始化 */Uart_Init(115200);LED_Exit_Init();KEY_Init();Spi2_Init();uint16_t leddata[]{0x7e, //00x30, //10x6D, //20x79, //30x33, //40x5B, //50x5F, //60x70, //70x7F, //80x7B, //90x77, //A0x7F, //B0x4E, //C0x7e, //D0x4F, //E0x47, //F0x37, //H0x00 //熄灭};delay_ms(50);Init_MAX7219();delay_ms(1000);Write_Max7219(0x0f, 0x00); //显示测试1测试结束正常显示0Write_Max7219(1,leddata[0]); //第一个数码管显示1Write_Max7219(2,leddata[1]);Write_Max7219(3,leddata[2]);Write_Max7219(4,leddata[3]); Write_Max7219(5,leddata[4]);Write_Max7219(6,leddata[5]);Write_Max7219(7,leddata[6]);Write_Max7219(8,leddata[7]); while (1){for(uint16_t i0;i18;i){Write_Max7219(1,leddata[i]);delay_ms(500);}}
}#include stm32f1xx_hal.hSPI_HandleTypeDef SPI2_Handle;//MAX7219
void Spi2_Init()
{SPI2_Handle.InstanceSPI2;//SPI2挂载在APB1总线上APB2总线36MHZSPI2_Handle.Init.BaudRatePrescalerSPI_BAUDRATEPRESCALER_16; //分频 36/162SPI2_Handle.Init.CLKPhaseSPI_PHASE_1EDGE; //第一个边沿捕获CPHASPI2_Handle.Init.CLKPolaritySPI_POLARITY_LOW; //CPOL时钟极性 SPI_POLARITY_HIGHSPI2_Handle.Init.CRCCalculationSPI_CRCCALCULATION_DISABLE; //是否开启CRC校验硬件自动校验主要看操作的从机使用否支持CRC校验SPI2_Handle.Init.DataSizeSPI_DATASIZE_8BIT;SPI2_Handle.Init.DirectionSPI_DIRECTION_1LINE; //单线半双工SPI2_Handle.Init.FirstBitSPI_FIRSTBIT_MSB; //高位先行SPI2_Handle.Init.TIModeSPI_TIMODE_DISABLE; //不支持TI模式SPI2_Handle.Init.ModeSPI_MODE_MASTER; //主机模式SPI2_Handle.Init.NSSSPI_NSS_SOFT; //NSS软件模式HAL_SPI_Init(SPI2_Handle);
}void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI2){__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_SPI2_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitType;//片选GPIO_InitType.ModeGPIO_MODE_OUTPUT_PP; //推挽输出 普通的IO口GPIO_InitType.PinGPIO_PIN_12;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB,GPIO_InitType); GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用推挽输出 复用为SPIGPIO_InitType.PinGPIO_PIN_13;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB,GPIO_InitType); //MISO 主机输入,从机输出GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用输入 复用为SPIGPIO_InitType.PinGPIO_PIN_15;GPIO_InitType.PullGPIO_NOPULL;HAL_GPIO_Init(GPIOB,GPIO_InitType); }}
#include stm32f1xx_hal.h
#include stdarg.h
#include stdio.h
#include SPI.h
#include UART.h
#include delay.h
/* address define */
#define NO_OP 0x00
#define DIGIT0 0x01
#define DIGIT1 0x02
#define DIGIT2 0x03
#define DIGIT3 0x04
#define DIGIT4 0x05
#define DIGIT5 0x06
#define DIGIT6 0x07
#define DIGIT7 0x08
#define DECODE_MODE 0x09 //译码控制寄存器
#define INTENSITY 0x0A // 亮度控制寄存器
#define SCAN_LIMIT 0x0B //扫描界限寄存器
#define SHUT_DOWN 0x0C //关断模式寄存器
#define DISPLAY_TEST 0x0F //显示测试寄存器
/* mode define */
#define NORMAL_MODE 0
#define NO_DECODE_D0_D7 0x00
#define DECODE_D0_ONLY 0x01
#define DECODE_D0_D3_ONLY 0x0F
#define DECODE_D0_D7 0xFF#define CS_ENABLE_MAX7291 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
#define CS_DISABLE_MAX7291 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET); //功能向MAX7219内部寄存器写入数据
//参数addr、dat
void Write_Max7219(uint8_t addr,uint8_t dat)
{CS_ENABLE_MAX7291; HAL_SPI_Transmit(SPI2_Handle,addr,1,1000); //写入地址 delay_us(10);//必须点阵不显示时可以延长此延时调试HAL_SPI_Transmit(SPI2_Handle,dat,1,1000); //写入地址 delay_us(10);//必须点阵不显示时可以延长此延时调试CS_DISABLE_MAX7291;
}//MAX7291初始化
void Init_MAX7219(void)
{Write_Max7219(0x09, 0x00); //译码方式不译码Write_Max7219(0x0a, 0x03); //亮度Write_Max7219(0x0b, 0x07); //扫描界限4个数码管显示Write_Max7219(0x0c, 0x01); //掉电模式0普通模式1Write_Max7219(0x0f, 0x01); //显示测试1测试结束正常显示0
} C中断方式--W25Q64 调用回调的时候说明它的收发已经完成。
#include stm32f1xx_hal.h
#include rcc.h
#include led.h
#include delay.h
#include UART.h
#include stdarg.h
#include stdio.h
#include key.h
#include SPI.h
#include w25q64.huint16_t i0;int main(void)
{HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */LED_Init(); /* LED初始化 */Uart_Init(115200);LED_Exit_Init();KEY_Init();Spi1_Init();W25q64_SectorErase(0);W25q64_ReadID();for(i0;i4096;i){ wbuff[i]0x66;}for(i0;i16;i){W25q64_WritePage(wbuff[i*256],i);}W25q64_ReadData(rbuff,0,4096);// for(i0;i4096;i)
// {
// printf(rbuff[%d]%x\r\n,i,rbuff[i]);
// }while (1){}
}#include stm32f1xx_hal.h
#include UART.h
#include stdarg.h
#include stdio.h
#include w25q64.h
uint8_t wbuff[4096];
uint8_t rbuff[4096];
SPI_HandleTypeDef SPI_Handle;void Spi1_Init()
{SPI_Handle.InstanceSPI1;//SPI1挂载在APB2总线上APB2总线72MHZSPI_Handle.Init.BaudRatePrescalerSPI_BAUDRATEPRESCALER_2; //分频SPI_Handle.Init.CLKPhaseSPI_PHASE_1EDGE; //第一个边沿捕获CPHASPI_Handle.Init.CLKPolaritySPI_POLARITY_LOW; //CPOL时钟极性SPI_Handle.Init.CRCCalculationSPI_CRCCALCULATION_DISABLE; //是否开启CRC校验硬件自动校验主要看操作的从机使用否支持CRC校验SPI_Handle.Init.DataSizeSPI_DATASIZE_8BIT;SPI_Handle.Init.DirectionSPI_DIRECTION_2LINES; //双线全双工SPI_Handle.Init.FirstBitSPI_FIRSTBIT_MSB; //高位先行SPI_Handle.Init.TIModeSPI_TIMODE_DISABLE; //不支持TI模式SPI_Handle.Init.ModeSPI_MODE_MASTER; //主机模式SPI_Handle.Init.NSSSPI_NSS_SOFT; //NSS软件模式HAL_SPI_Init(SPI_Handle);
}void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI1){__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_SPI1_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitType;HAL_NVIC_SetPriority(SPI1_IRQn,3,2);HAL_NVIC_EnableIRQ(SPI1_IRQn);GPIO_InitType.ModeGPIO_MODE_OUTPUT_PP; //推挽输出 普通的IO口GPIO_InitType.PinGPIO_PIN_0;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA,GPIO_InitType); GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用推挽输出 复用为SPIGPIO_InitType.PinGPIO_PIN_5;GPIO_InitType.SpeedGPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,GPIO_InitType); //MISO 主机输入,从机输出GPIO_InitType.ModeGPIO_MODE_AF_INPUT; //复用输入 复用为SPIGPIO_InitType.PinGPIO_PIN_6;GPIO_InitType.PullGPIO_NOPULL;HAL_GPIO_Init(GPIOA,GPIO_InitType); //MOSI 主机输出,从机输入GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用推挽输出 复用为SPIGPIO_InitType.PinGPIO_PIN_7;GPIO_InitType.SpeedGPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,GPIO_InitType); }}void SPI1_IRQHandler()
{HAL_SPI_IRQHandler(SPI_Handle);}
//IT的API函数执行完毕开启中断接收函数但是不代表接收操作的完成。
//调用回调函数的时候表示接收完毕。
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI1){for(uint16_t i0;i4096;i){CS_DISABLE;printf(rbuff[%d]%x\r\n,i,rbuff[i]);}}
}
#include stm32f1xx_hal.h
#include stdarg.h
#include stdio.h
#include SPI.h
#include stdarg.h
#include stdio.h
#include UART.h
#define CS_ENABLE HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
#define CS_DISABLE HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);/*** brief 查看busy位是否忙碌.*/
void W25q64_Busy(void)
{ uint8_t cmd[2],data[2];cmd[0]0x05;cmd[1]0xFF;do{CS_ENABLE;HAL_SPI_TransmitReceive(SPI_Handle,cmd,data,2,1000);CS_DISABLE;}while((data[1] 0x01)0x01); //busy为0不忙}
/*** brief 写使能.*/
void W25q64_WriteEnable(void)
{uint8_t cmd;cmd0x06;W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,1,1000);CS_DISABLE;
}/*** brief 擦除一个扇区的数据4K;4*10244096* param 擦除第几页的数据 */
void W25q64_SectorErase(uint32_t Sectornum)
{uint8_t cmd[4];cmd[0]0x20;cmd[1](Sectornum*4096)16;cmd[2](Sectornum*4096)8;cmd[3](Sectornum*4096)0;W25q64_WriteEnable();W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,4,1000);CS_DISABLE;
}/*** brief 写入一页数据一页256字节* param data: 写入的数据* param PageNum给第几页写入数据*/
void W25q64_WritePage(uint8_t * data,uint32_t PageNum)
{uint8_t cmd[4];cmd[0]0x02;cmd[1](PageNum*256)16;cmd[2](PageNum*256)8;cmd[3](PageNum*256)0;W25q64_WriteEnable();W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,4,1000);HAL_SPI_Transmit(SPI_Handle,data,256,5000); //sizeof(data)CS_DISABLE;
}/*** brief 读取数据* param *rdata 读取数据存放的地址* param addr 读取第几页* param len 读取数据的长度几个字节* retval */
void W25q64_ReadData(uint8_t *rdata,uint32_t addr ,uint32_t len)
{uint8_t cmd[4];cmd[0]0x03;cmd[1]addr16;cmd[2]addr8;cmd[3]addr0;W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,4,1000);HAL_SPI_Receive_IT(SPI_Handle,rdata,len);//CS_DISABLE;}/*** brief 读取ID.*/
void W25q64_ReadID()
{uint8_t cmd[1],data_id[3];cmd[0]0x9F;W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,1,1000);HAL_SPI_Receive(SPI_Handle,data_id,sizeof(data_id),50000);CS_DISABLE;printf(W25q64的ID为制造商ID%02X 设备ID%02X 容量ID%02X\r\n, data_id[0], data_id[1], data_id[2]); }
D:MDA----W25Q64 #include stm32f1xx_hal.h
#include rcc.h
#include led.h
#include delay.h
#include UART.h
#include stdarg.h
#include stdio.h
#include key.h
#include SPI.h
#include w25q64.huint16_t i0;int main(void)
{HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */LED_Init(); /* LED初始化 */Uart_Init(115200);LED_Exit_Init();KEY_Init();Spi1_Init();W25q64_SectorErase(0);W25q64_ReadID();for(i0;i4096;i){ wbuff[i]0x44;}for(i0;i16;i){W25q64_WritePage(wbuff[i*256],i);}W25q64_ReadData(rbuff,0,4096);while (1){}
}#include stm32f1xx_hal.h
#include UART.h
#include stdarg.h
#include stdio.h
#include w25q64.h
uint8_t wbuff[4096];
uint8_t rbuff[4096];
SPI_HandleTypeDef SPI_Handle;
DMA_HandleTypeDef DMA_HandleTX;
DMA_HandleTypeDef DMA_HandleRX;void Spi1_Init()
{SPI_Handle.InstanceSPI1;//SPI1挂载在APB2总线上APB2总线72MHZSPI_Handle.Init.BaudRatePrescalerSPI_BAUDRATEPRESCALER_2; //分频SPI_Handle.Init.CLKPhaseSPI_PHASE_1EDGE; //第一个边沿捕获CPHASPI_Handle.Init.CLKPolaritySPI_POLARITY_LOW; //CPOL时钟极性SPI_Handle.Init.CRCCalculationSPI_CRCCALCULATION_DISABLE; //是否开启CRC校验硬件自动校验主要看操作的从机使用否支持CRC校验SPI_Handle.Init.DataSizeSPI_DATASIZE_8BIT;SPI_Handle.Init.DirectionSPI_DIRECTION_2LINES; //双线全双工SPI_Handle.Init.FirstBitSPI_FIRSTBIT_MSB; //高位先行SPI_Handle.Init.TIModeSPI_TIMODE_DISABLE; //不支持TI模式SPI_Handle.Init.ModeSPI_MODE_MASTER; //主机模式SPI_Handle.Init.NSSSPI_NSS_SOFT; //NSS软件模式HAL_SPI_Init(SPI_Handle);
}void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI1){__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_SPI1_CLK_ENABLE();__HAL_RCC_DMA1_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitType;// HAL_NVIC_SetPriority(SPI1_IRQn,3,2);
// HAL_NVIC_EnableIRQ(SPI1_IRQn);//MDA通道6配置--发送数据DMA_HandleTX.InstanceDMA1_Channel3;//传输方向内存数组---外设(SPI的DR寄存器)DMA_HandleTX.Init.DirectionDMA_MEMORY_TO_PERIPH;DMA_HandleTX.Init.MemDataAlignmentDMA_MDATAALIGN_BYTE; //内存数据宽度DMA_HandleTX.Init.MemIncDMA_MINC_ENABLE; //存储区数组地址自增DMA_HandleTX.Init.ModeDMA_NORMAL;DMA_HandleTX.Init.PeriphDataAlignmentDMA_PDATAALIGN_BYTE;//外设数据宽度DMA_HandleTX.Init.PeriphIncDMA_PINC_DISABLE;//外设地址不自增SPI的DR寄存器DMA_HandleTX.Init.PriorityDMA_PRIORITY_MEDIUM; //优先级__HAL_LINKDMA(SPI_Handle,hdmatx,DMA_HandleTX); //双向链接//__HAL_LINKDMA(hspi,hdmatx,DMA_HandleTX); //双向链接HAL_DMA_Init(DMA_HandleTX);HAL_NVIC_SetPriority(DMA1_Channel3_IRQn,1,2);HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);//MDA通道7配置---接收数据DMA_HandleRX.InstanceDMA1_Channel2;//传输方向外设SPI的DR寄存器 --- 内存数组DMA_HandleRX.Init.DirectionDMA_PERIPH_TO_MEMORY;DMA_HandleRX.Init.MemDataAlignmentDMA_MDATAALIGN_BYTE; //内存数据宽度DMA_HandleRX.Init.MemIncDMA_MINC_ENABLE; //存储区地址自增DMA_HandleRX.Init.ModeDMA_NORMAL;DMA_HandleRX.Init.PeriphDataAlignmentDMA_PDATAALIGN_BYTE;//外设数据宽度DMA_HandleRX.Init.PeriphIncDMA_PINC_DISABLE;//外设地址不自增DMA_HandleRX.Init.PriorityDMA_PRIORITY_MEDIUM; //优先级__HAL_LINKDMA(SPI_Handle,hdmarx,DMA_HandleRX); //双向链接//__HAL_LINKDMA(hi2c,hdmarx,DMA_HandleRX); //双向链接HAL_DMA_Init(DMA_HandleRX);HAL_NVIC_SetPriority(DMA1_Channel2_IRQn,1,2);HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);GPIO_InitType.ModeGPIO_MODE_OUTPUT_PP; //推挽输出 普通的IO口GPIO_InitType.PinGPIO_PIN_0;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA,GPIO_InitType); GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用推挽输出 复用为SPIGPIO_InitType.PinGPIO_PIN_5;GPIO_InitType.SpeedGPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,GPIO_InitType); //MISO 主机输入,从机输出GPIO_InitType.ModeGPIO_MODE_AF_INPUT; //复用输入 复用为SPIGPIO_InitType.PinGPIO_PIN_6;GPIO_InitType.PullGPIO_NOPULL;HAL_GPIO_Init(GPIOA,GPIO_InitType); //MOSI 主机输出,从机输入GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用推挽输出 复用为SPIGPIO_InitType.PinGPIO_PIN_7;GPIO_InitType.SpeedGPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,GPIO_InitType); }}//void SPI1_IRQHandler()
//{
// HAL_SPI_IRQHandler(SPI_Handle);//}void DMA1_Channel2_IRQHandler()
{HAL_DMA_IRQHandler(DMA_HandleRX);}void DMA1_Channel3_IRQHandler()
{HAL_DMA_IRQHandler(DMA_HandleTX);}
//DMA的API函数执行完毕开启中断接收函数但是不代表接收操作的完成。
//调用回调函数的时候表示接收完毕。
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI1){for(uint16_t i0;i4096;i){CS_DISABLE;printf(rbuff[%d]%x\r\n,i,rbuff[i]);}}
}
#include stm32f1xx_hal.h
#include stdarg.h
#include stdio.h
#include SPI.h
#include stdarg.h
#include stdio.h
#include UART.h
#define CS_ENABLE HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
#define CS_DISABLE HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);/*** brief 查看busy位是否忙碌.*/
void W25q64_Busy(void)
{ uint8_t cmd[2],data[2];cmd[0]0x05;cmd[1]0xFF;do{CS_ENABLE;HAL_SPI_TransmitReceive(SPI_Handle,cmd,data,2,1000);CS_DISABLE;}while((data[1] 0x01)0x01); //busy为0不忙}
/*** brief 写使能.*/
void W25q64_WriteEnable(void)
{uint8_t cmd;cmd0x06;W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,1,1000);CS_DISABLE;
}/*** brief 擦除一个扇区的数据4K;4*10244096* param 擦除第几页的数据 */
void W25q64_SectorErase(uint32_t Sectornum)
{uint8_t cmd[4];cmd[0]0x20;cmd[1](Sectornum*4096)16;cmd[2](Sectornum*4096)8;cmd[3](Sectornum*4096)0;W25q64_WriteEnable();W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,4,1000);CS_DISABLE;
}/*** brief 写入一页数据一页256字节* param data: 写入的数据* param PageNum给第几页写入数据*/
void W25q64_WritePage(uint8_t * data,uint32_t PageNum)
{uint8_t cmd[4];cmd[0]0x02;cmd[1](PageNum*256)16;cmd[2](PageNum*256)8;cmd[3](PageNum*256)0;W25q64_WriteEnable();W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,4,1000);HAL_SPI_Transmit(SPI_Handle,data,256,5000); //sizeof(data)CS_DISABLE;
}/*** brief 读取数据* param *rdata 读取数据存放的地址* param addr 读取第几页* param len 读取数据的长度几个字节* retval */
void W25q64_ReadData(uint8_t *rdata,uint32_t addr ,uint32_t len)
{uint8_t cmd[4];cmd[0]0x03;cmd[1]addr16;cmd[2]addr8;cmd[3]addr0;W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,4,1000);HAL_SPI_Receive_DMA(SPI_Handle,rdata,len);//CS_DISABLE;}/*** brief 读取ID.*/
void W25q64_ReadID()
{uint8_t cmd[1],data_id[3];cmd[0]0x9F;W25q64_Busy();CS_ENABLE;HAL_SPI_Transmit(SPI_Handle,cmd,1,1000);HAL_SPI_Receive(SPI_Handle,data_id,sizeof(data_id),50000);CS_DISABLE;printf(W25q64的ID为制造商ID%02X 设备ID%02X 容量ID%02X\r\n, data_id[0], data_id[1], data_id[2]); }
主从通信
A:中断主机身份不改变 发现问题2个板子的SPI通信正常主机可以正常给从机发送数据但是从机给主机发送数据的数据顺序会乱。
解决换线一定要共电源和共地下面所有的主从通信必须遵守这个
主机代码 #include stm32f1xx_hal.h
#include rcc.h
#include led.h
#include delay.h
#include UART.h
#include stdarg.h
#include stdio.h
#include key.h
#include SPI.h
#include MAX7219.hint main(void)
{HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */LED_Init(); /* LED初始化 */Uart_Init(115200);LED_Exit_Init();KEY_Init();Spi1_Init();while (1){if(KEY_Scan()){printf(PA0按下,主机发送数据\r\n);HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);HAL_SPI_TransmitReceive_IT(SPI_Handle,wbuff,rbuff,10);}}
}#include stm32f1xx_hal.h
#include UART.h
#include stdarg.h
#include stdio.hSPI_HandleTypeDef SPI_Handle;uint8_t wbuff[10]{10,11,12,13,14,15,16,17,18,19};
uint8_t rbuff[10];
void Spi1_Init()
{//主机SPI_Handle.InstanceSPI1;//SPI1挂载在APB2总线上APB2总线72MHZSPI_Handle.Init.BaudRatePrescalerSPI_BAUDRATEPRESCALER_128; //分频 72/2560.60MHZSPI_Handle.Init.CLKPhaseSPI_PHASE_2EDGE; //第二个边沿捕获CPHASPI_Handle.Init.CLKPolaritySPI_POLARITY_HIGH; //CPOL时钟极性SPI_Handle.Init.CRCCalculationSPI_CRCCALCULATION_DISABLE; //是否开启CRC校验硬件自动校验主要看操作的从机使用否支持CRC校验SPI_Handle.Init.DataSizeSPI_DATASIZE_8BIT;SPI_Handle.Init.DirectionSPI_DIRECTION_2LINES; //双线全双工SPI_Handle.Init.FirstBitSPI_FIRSTBIT_MSB; //高位先行SPI_Handle.Init.TIModeSPI_TIMODE_DISABLE; //不支持TI模式SPI_Handle.Init.ModeSPI_MODE_MASTER; //主机模式SPI_Handle.Init.NSSSPI_NSS_SOFT; //NSS软件模式HAL_SPI_Init(SPI_Handle);
}void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI1){__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_SPI1_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitType;HAL_NVIC_SetPriority(SPI1_IRQn,3,1);HAL_NVIC_EnableIRQ(SPI1_IRQn);GPIO_InitType.ModeGPIO_MODE_OUTPUT_PP; //推挽输出 普通的IO口GPIO_InitType.PinGPIO_PIN_4;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA,GPIO_InitType); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用推挽输出 复用为SPIGPIO_InitType.PinGPIO_PIN_5|GPIO_PIN_7;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA,GPIO_InitType); GPIO_InitType.ModeGPIO_MODE_AF_INPUT; //复用输入 复用为SPIGPIO_InitType.PinGPIO_PIN_6;GPIO_InitType.PullGPIO_NOPULL;HAL_GPIO_Init(GPIOA,GPIO_InitType); }}void SPI1_IRQHandler()
{HAL_SPI_IRQHandler(SPI_Handle);}void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI1){HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);for(uint8_t i0;i10;i){printf(rbuff[%d]%d\r\n,i,rbuff[i]);}}
}
从机代码
#include stm32f1xx_hal.h
#include rcc.h
#include led.h
#include delay.h
#include UART.h
#include stdarg.h
#include stdio.h
#include key.h
#include SPI.h
#include MAX7219.hint main(void)
{HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */LED_Init(); /* LED初始化 */Uart_Init(115200);LED_Exit_Init();KEY_Init();Spi2_Init();HAL_SPI_TransmitReceive_IT(SPI2_Handle,w_buff,r_buff,10);while (1){}
}#include stm32f1xx_hal.h
#include UART.h
#include stdarg.h
#include stdio.hSPI_HandleTypeDef SPI2_Handle;uint8_t w_buff[10]{0,1,2,3,4,5,6,7,8,9};
uint8_t r_buff[10];void Spi2_Init()
{//从机SPI2_Handle.InstanceSPI2;//SPI2挂载在APB1总线上APB2总线36MHZSPI2_Handle.Init.BaudRatePrescalerSPI_BAUDRATEPRESCALER_256; //分频 36/2560.14SPI2_Handle.Init.CLKPhaseSPI_PHASE_2EDGE; //第二个边沿捕获CPHASPI2_Handle.Init.CLKPolaritySPI_POLARITY_HIGH; //CPOL时钟极性SPI2_Handle.Init.CRCCalculationSPI_CRCCALCULATION_DISABLE; //是否开启CRC校验硬件自动校验主要看操作的从机使用否支持CRC校验SPI2_Handle.Init.DataSizeSPI_DATASIZE_8BIT;SPI2_Handle.Init.DirectionSPI_DIRECTION_2LINES; //双线全双工SPI2_Handle.Init.FirstBitSPI_FIRSTBIT_MSB; //高位先行SPI2_Handle.Init.TIModeSPI_TIMODE_DISABLE; //不支持TI模式SPI2_Handle.Init.ModeSPI_MODE_SLAVE; //从机模式SPI2_Handle.Init.NSSSPI_NSS_HARD_INPUT; //NSS硬件模式HAL_SPI_Init(SPI2_Handle);}void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI2){__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_SPI2_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitType;HAL_NVIC_SetPriority(SPI2_IRQn,3,1);HAL_NVIC_EnableIRQ(SPI2_IRQn);// //片选
// GPIO_InitType.ModeGPIO_MODE_INPUT; //输入 普通的IO口
// GPIO_InitType.PinGPIO_PIN_12;
// GPIO_InitType.PullGPIO_NOPULL;
// HAL_GPIO_Init(GPIOB,GPIO_InitType); // 配置为 SPI2_Handle.Init.NSSSPI_NSS_HARD_INPUT; //NSS硬件模式
// 从机片选不用IO口的配置GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用推挽输出 复用为SPIGPIO_InitType.PinGPIO_PIN_14;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB,GPIO_InitType); //MISO 主机输入,从机输出GPIO_InitType.ModeGPIO_MODE_AF_INPUT; //复用输入 复用为SPIGPIO_InitType.PinGPIO_PIN_13|GPIO_PIN_15;GPIO_InitType.PullGPIO_NOPULL;HAL_GPIO_Init(GPIOB,GPIO_InitType); }}void SPI2_IRQHandler()
{HAL_SPI_IRQHandler(SPI2_Handle);}void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI2){for(uint8_t i0;i10;i){printf(rbuff[%d]%d\r\n,i,r_buff[i]);}HAL_SPI_TransmitReceive_IT(SPI2_Handle,w_buff,r_buff,10);}
}B:中断DMA 主机代码和上面的A:中断主机身份不改变一样只是把从机改为DMA模式
从机代码
#include stm32f1xx_hal.h
#include rcc.h
#include led.h
#include delay.h
#include UART.h
#include stdarg.h
#include stdio.h
#include key.h
#include SPI.h
#include MAX7219.hint main(void)
{HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */LED_Init(); /* LED初始化 */Uart_Init(115200);LED_Exit_Init();KEY_Init();Spi2_Init();HAL_SPI_TransmitReceive_DMA(SPI2_Handle,wbuff,rbuff,10);printf(从机串口正常\r\n);while (1){}
}
#include stm32f1xx_hal.h
#include UART.h
#include stdarg.h
#include stdio.hSPI_HandleTypeDef SPI2_Handle;
DMA_HandleTypeDef DMA_HandleTX;
DMA_HandleTypeDef DMA_HandleRX;
uint8_t wbuff[10]{10,11,12,13,14,15,16,17,18,19};
uint8_t rbuff[10];void Spi2_Init()
{//从机SPI2_Handle.InstanceSPI2;//SPI2挂载在APB1总线上APB2总线36MHZSPI2_Handle.Init.BaudRatePrescalerSPI_BAUDRATEPRESCALER_128; //分频 36/1280.28MHZSPI2_Handle.Init.CLKPhaseSPI_PHASE_2EDGE; //第二个边沿捕获CPHASPI2_Handle.Init.CLKPolaritySPI_POLARITY_HIGH; //CPOL时钟极性SPI2_Handle.Init.CRCCalculationSPI_CRCCALCULATION_DISABLE; //是否开启CRC校验硬件自动校验主要看操作的从机使用否支持CRC校验SPI2_Handle.Init.DataSizeSPI_DATASIZE_8BIT;SPI2_Handle.Init.DirectionSPI_DIRECTION_2LINES; //双线全双工SPI2_Handle.Init.FirstBitSPI_FIRSTBIT_MSB; //高位先行SPI2_Handle.Init.TIModeSPI_TIMODE_DISABLE; //不支持TI模式SPI2_Handle.Init.ModeSPI_MODE_SLAVE; //从机模式SPI2_Handle.Init.NSSSPI_NSS_HARD_INPUT; //NSS输入HAL_SPI_Init(SPI2_Handle);
}void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI2){__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_SPI2_CLK_ENABLE();__HAL_RCC_DMA1_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitType;//MDA通道5配置--发送数据DMA_HandleTX.InstanceDMA1_Channel5;//传输方向内存数组---外设(SPI的DR寄存器)DMA_HandleTX.Init.DirectionDMA_MEMORY_TO_PERIPH;DMA_HandleTX.Init.MemDataAlignmentDMA_MDATAALIGN_BYTE; //内存数据宽度DMA_HandleTX.Init.MemIncDMA_MINC_ENABLE; //存储区数组地址自增DMA_HandleTX.Init.ModeDMA_NORMAL;DMA_HandleTX.Init.PeriphDataAlignmentDMA_PDATAALIGN_BYTE;//外设数据宽度DMA_HandleTX.Init.PeriphIncDMA_PINC_DISABLE;//外设地址不自增SPI的DR寄存器DMA_HandleTX.Init.PriorityDMA_PRIORITY_MEDIUM; //优先级__HAL_LINKDMA(SPI2_Handle,hdmatx,DMA_HandleTX); //双向链接//__HAL_LINKDMA(hspi,hdmatx,DMA_HandleTX); //双向链接HAL_DMA_Init(DMA_HandleTX);HAL_NVIC_SetPriority(DMA1_Channel5_IRQn,1,2);HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);//MDA通道4配置---接收数据DMA_HandleRX.InstanceDMA1_Channel4;//传输方向外设SPI的DR寄存器 --- 内存数组DMA_HandleRX.Init.DirectionDMA_PERIPH_TO_MEMORY;DMA_HandleRX.Init.MemDataAlignmentDMA_MDATAALIGN_BYTE; //内存数据宽度DMA_HandleRX.Init.MemIncDMA_MINC_ENABLE; //存储区地址自增DMA_HandleRX.Init.ModeDMA_NORMAL;DMA_HandleRX.Init.PeriphDataAlignmentDMA_PDATAALIGN_BYTE;//外设数据宽度DMA_HandleRX.Init.PeriphIncDMA_PINC_DISABLE;//外设地址不自增DMA_HandleRX.Init.PriorityDMA_PRIORITY_MEDIUM; //优先级__HAL_LINKDMA(SPI2_Handle,hdmarx,DMA_HandleRX); //双向链接//__HAL_LINKDMA(hi2c,hdmarx,DMA_HandleRX); //双向链接HAL_DMA_Init(DMA_HandleRX);HAL_NVIC_SetPriority(DMA1_Channel4_IRQn,1,2);HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用推挽输出 复用为SPIGPIO_InitType.PinGPIO_PIN_14;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB,GPIO_InitType); //MISO 主机输入,从机输出GPIO_InitType.ModeGPIO_MODE_AF_INPUT; //复用输入 复用为SPIGPIO_InitType.PinGPIO_PIN_13|GPIO_PIN_15;GPIO_InitType.PullGPIO_NOPULL;HAL_GPIO_Init(GPIOB,GPIO_InitType); }}void DMA1_Channel4_IRQHandler()
{HAL_DMA_IRQHandler(DMA_HandleRX);}void DMA1_Channel5_IRQHandler()
{HAL_DMA_IRQHandler(DMA_HandleTX);}void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI2){for(uint8_t i0;i10;i){printf(rbuff[%d]%d\r\n,i,rbuff[i]);}HAL_SPI_TransmitReceive_DMA(SPI2_Handle,wbuff,rbuff,10);}
}C多主机通信--主从身份可以改变 PA3控制对方的PA4PA4CS片选
主机和从机可以使用这一个代码只需要把里面发送的数据改了就ok了其他代码部分都不需要改。
把对方拉为从机 走的流程 while (1){if(KEY_Scan()){printf(PA0按下,把对方拉为从机发送数据\r\n);HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);HAL_Delay(20);HAL_SPI_TransmitReceive_IT(SPI_Handle,wbuff,rbuff,10);}
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI1){HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET); }}
被对面拉低为从机被拉低产生MODE错误进入
//主机配拉低被拉低产生MODE错误进入这个中断回调函数
//在这个错误中断回调函数中把它变为从机
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI1){if(hspi-ErrorCodeHAL_SPI_ERROR_MODF){printf(被拉成从机\r\n);HAL_SPI_DeInit(SPI_Handle); //清除以前的配置Spi1_SInit(); //重新配置为从机HAL_SPI_TransmitReceive_IT(SPI_Handle,wbuff,rbuff,10);}}
}void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI1){for(uint8_t i0;i10;i){printf(rbuff[%d]%d\r\n,i,rbuff[i]);}Spi1_MInit(); //被对方拉低接收数据接收完毕在变为主模式以便下一次使用}} __HAL_SPI_ENABLE(SPI_Handle);__HAL_SPI_ENABLE_IT(SPI_Handle,SPI_IT_ERR); 手动打开错误中断被拉为从机的时候发送这个错误调用错误中断回调函数 __HAL_SPI_ENABLE(SPI_Handle)这个是在接收和发送函数内部的HAL帮助我们调用的。我们现在都是主机不能调用收发函数在一主一从的时候才可以正常通信两个都为主机时没有办法通信。我们需要自己手动打开SPI的接口。 代码
#include stm32f1xx_hal.h
#include rcc.h
#include led.h
#include delay.h
#include UART.h
#include stdarg.h
#include stdio.h
#include key.h
#include SPI.h
#include MAX7219.hint main(void)
{HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */LED_Init(); /* LED初始化 */Uart_Init(115200);LED_Exit_Init();KEY_Init();Spi1_MInit();while (1){if(KEY_Scan()){printf(PA0按下,把对方拉为从机发送数据\r\n);HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);HAL_Delay(20);HAL_SPI_TransmitReceive_IT(SPI_Handle,wbuff,rbuff,10);}}
}
#include stm32f1xx_hal.h
#include UART.h
#include stdarg.h
#include stdio.hSPI_HandleTypeDef SPI_Handle;uint8_t wbuff[10]{1,2,3,4,5,6,7,8,9,10};uint8_t rbuff[10];
void Spi1_MInit()
{//主机SPI_Handle.InstanceSPI1;//SPI1挂载在APB2总线上APB2总线72MHZSPI_Handle.Init.BaudRatePrescalerSPI_BAUDRATEPRESCALER_256; //分频 72/2560.28MHZSPI_Handle.Init.CLKPhaseSPI_PHASE_2EDGE; //第二个边沿捕获CPHASPI_Handle.Init.CLKPolaritySPI_POLARITY_HIGH; //CPOL时钟极性SPI_Handle.Init.CRCCalculationSPI_CRCCALCULATION_DISABLE; //是否开启CRC校验硬件自动校验主要看操作的从机使用否支持CRC校验SPI_Handle.Init.DataSizeSPI_DATASIZE_8BIT;SPI_Handle.Init.DirectionSPI_DIRECTION_2LINES; //双线全双工SPI_Handle.Init.FirstBitSPI_FIRSTBIT_MSB; //高位先行SPI_Handle.Init.TIModeSPI_TIMODE_DISABLE; //不支持TI模式SPI_Handle.Init.ModeSPI_MODE_MASTER; //主机模式SPI_Handle.Init.NSSSPI_NSS_HARD_INPUT; //NSS硬件输入HAL_SPI_Init(SPI_Handle);__HAL_SPI_ENABLE(SPI_Handle);__HAL_SPI_ENABLE_IT(SPI_Handle,SPI_IT_ERR); //手动打开错误中断
}void Spi1_SInit()
{//从机SPI_Handle.InstanceSPI1;//SPI1挂载在APB2总线上APB2总线72MHZSPI_Handle.Init.BaudRatePrescalerSPI_BAUDRATEPRESCALER_256; //分频 72/2560.28MHZSPI_Handle.Init.CLKPhaseSPI_PHASE_2EDGE; //第二个边沿捕获CPHASPI_Handle.Init.CLKPolaritySPI_POLARITY_HIGH; //CPOL时钟极性SPI_Handle.Init.CRCCalculationSPI_CRCCALCULATION_DISABLE; //是否开启CRC校验硬件自动校验主要看操作的从机使用否支持CRC校验SPI_Handle.Init.DataSizeSPI_DATASIZE_8BIT;SPI_Handle.Init.DirectionSPI_DIRECTION_2LINES; //双线全双工SPI_Handle.Init.FirstBitSPI_FIRSTBIT_MSB; //高位先行SPI_Handle.Init.TIModeSPI_TIMODE_DISABLE; //不支持TI模式SPI_Handle.Init.ModeSPI_MODE_SLAVE; //从机模式SPI_Handle.Init.NSSSPI_NSS_HARD_INPUT; //硬件输入HAL_SPI_Init(SPI_Handle);}void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI1){__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_SPI1_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitType;HAL_NVIC_SetPriority(SPI1_IRQn,3,1);HAL_NVIC_EnableIRQ(SPI1_IRQn);GPIO_InitType.ModeGPIO_MODE_OUTPUT_PP; //推挽输出 普通的IO口GPIO_InitType.PinGPIO_PIN_3;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA,GPIO_InitType); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);if(hspi-Init.ModeSPI_MODE_MASTER){ //主机GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用推挽输出 复用为SPIGPIO_InitType.PinGPIO_PIN_5|GPIO_PIN_7;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA,GPIO_InitType); GPIO_InitType.ModeGPIO_MODE_AF_INPUT; //复用输入 复用为SPIGPIO_InitType.PinGPIO_PIN_6;GPIO_InitType.PullGPIO_NOPULL;HAL_GPIO_Init(GPIOA,GPIO_InitType); }else {//从机 GPIO_InitType.ModeGPIO_MODE_AF_INPUT; //复用输入 复用为SPIGPIO_InitType.PinGPIO_PIN_5|GPIO_PIN_7;GPIO_InitType.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA,GPIO_InitType); GPIO_InitType.ModeGPIO_MODE_AF_PP; //复用推挽输出 复用为SPIGPIO_InitType.PinGPIO_PIN_6;GPIO_InitType.PullGPIO_NOPULL;HAL_GPIO_Init(GPIOA,GPIO_InitType); }}}void SPI1_IRQHandler()
{HAL_SPI_IRQHandler(SPI_Handle);}void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI1){HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);for(uint8_t i0;i10;i){printf(rbuff[%d]%d\r\n,i,rbuff[i]);}Spi1_MInit(); //被对方拉低接收数据接收完毕在变为主模式以便下一次使用}}//主机配拉低被拉低产生MODE错误进入这个中断回调函数
//在这个错误中断回调函数中把它变为从机
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{if(hspi-InstanceSPI1){if(hspi-ErrorCodeHAL_SPI_ERROR_MODF){printf(被拉成从机\r\n);HAL_SPI_DeInit(SPI_Handle); //清除以前的配置Spi1_SInit(); //重新配置为从机HAL_SPI_TransmitReceive_IT(SPI_Handle,wbuff,rbuff,10);}}
}