关于STM32的SPI使用(中断方式)的探讨

还没有用过STM32的SPI功能, 所以想尝试着做做看.

以前做串口通信都是用中断方式做的, 所以做SPI通信, 首先想到的就是用中断方式做, 网上有一些例程, 但是好像也有没有解释的很清楚的, 至少我没有理解.

以下我将从自己的认知来写一下, 大神绕过, 小白可以看看, 来看看是否有你自己的盲点, 本文也只是描述我自己碰到的问题的点, 不包含整个代码.

1. 关于GPIO口模式的设置
输出口没有什么可说的, 都是GPIO_Mode_AF_PP, 但是输入口模式, 需要注意, 网上有的教程是让设置成GPIO_Mode_IN_FLOATING, 实测这个模式不行, 需要使用GPIO_Mode_IPU模式, 使用floating模式时, 我监控接收到的数跟主机发送过来的数有出入, 有时候不一样, 改成IPU模式, 没有异常. 不要轻信网上的一些帖子, 别拿他们的当教条!! 要持怀疑态度.


以下是我初始化SPI的代码

		//因为SPI1的输出要靠PA5&PA6&PA7来完成, 所以须先初始化PA5&PA6&PA7的工作模式
		//注意SPI引脚是否和JATG口或者SWD口复用.
		//先初始化引脚的模式
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);		//初始化管脚的工作模式之前不写这一句也可以
		//初始化管脚
		//PA5_SPI1_CLK
		PAx.GPIO_Pin = GPIO_Pin_5;
		PAx.GPIO_Mode = GPIO_Mode_IPU;//GPIO_Mode_IN_FLOATING;
		//PAx.GPIO_Mode = GPIO_Mode_IN_FLOATING;//GPIO_Mode_IN_FLOATING;
		PAx.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA, &PAx);
		//PA6_SPI1_MISO
		PAx.GPIO_Pin = GPIO_Pin_6;
		PAx.GPIO_Mode = GPIO_Mode_AF_PP;//GPIO_Mode_Out_PP;
		PAx.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA, &PAx);
		//PA7_SPI1_MOSI
		PAx.GPIO_Pin = GPIO_Pin_7;
		PAx.GPIO_Mode = GPIO_Mode_IPU;//GPIO_Mode_IN_FLOATING;
		//PAx.GPIO_Mode = GPIO_Mode_IN_FLOATING;//GPIO_Mode_IN_FLOATING;
		PAx.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA, &PAx);
		
		//打开外设时钟
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

		//初始化SPI相关寄存器
		SPIxInit.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
		SPIxInit.SPI_Mode = SPI_Mode_Slave;
		SPIxInit.SPI_DataSize = SPI_DataSize_8b;
		SPIxInit.SPI_CPOL = SPI_CPOL_Low;
		SPIxInit.SPI_CPHA = SPI_CPHA_1Edge;
		SPIxInit.SPI_NSS = SPI_NSS_Soft;
		SPIxInit.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
		SPIxInit.SPI_FirstBit = SPI_FirstBit_MSB;
		SPI_Init(SPI1, &SPIxInit);

2. 关于SPI的发送中断
这里说下SPI的发送中断, 主要是主机的SPI, 这个中断很有意思, SPI_I2S_IT_TXE, 这个中断叫做"发送缓冲区空中断", 仔细理解这个名字, 当发送缓冲区为空时, 就会产生这个中断, 所以, 如果当在初始化SPI时, 直接打开这个中断, 程序会直接跑到SPI的中断服务程序中, 一直跳不出来, 原因就是此时SPI发送寄存器一直是空的, 所以, 感觉这个中断只有在要发送数据以后打开, 并且在发送完一帧数据后, 在中断服务程序中把该中断关闭. 至于那个标志 清不清的无所谓了, 反正也要自己做判断

3. 关于SPI的接收中断
也不知道是我自己理解不对, 还是作者就这么设计的这个中断, 这个中断的名称为:SPI_I2S_IT_RXNE, 叫做"接收缓冲区非空中断", 也需要自己理解这个中断, 个人实际应该叫接收缓冲区填满中断, 这个不是重点, 重点是如何清除这个标志, 其它一些外设清中断标志位是使用XXXX_ClearITPendingBit()这个函数, 但是这里不能这么用, 这里的用法是使用SPI_I2S_ReceiveData()读取缓冲区里面的数据, 使用完该函数后, 该中断标志自动清除, 经测试SPI_I2S_ClearITPendingBit(SPI1, SPI_I2S_IT_RXNE);这个是无效的.

总结: 我认为值得分享的就这三条, 其它都是常规操作, 以上内容来源于STM32的使用手册和实践

有感兴趣的可以留言交流

 

HAL (Hardware Abstraction Layer) 是针对各种硬件的抽象层,可以方便地在不同的处理器上交叉使用SPI(Serial Peripheral Interface)是三线式串行总线,适用于外围设备与主机芯片间的高速短距离通信,常用于控制设备的数据传输和通信。 在HAL SPI中断收发中,当外设有数据传输请求时,主机芯片触发中断并进去中断服务程序。执行中断服务程序之前,需要设置SPI控制寄存器来配置SPI通信的参数,例如通信模式、数据传输速率、数据帧格式、时钟相位等。然后,利用SPI数据寄存器进行数据发送和接收,并通过中断寄存器控制中断的开启和关闭。 在HAL SPI中断收发中,中断服务程序通常包括以下的操作过程: 1.读取ISR寄存器,判断数据是否已经发送或接收完成。 2.将发送数据写入SPI发送缓冲区(Tx Buffer)中。 3.等待发送完成,并将接收数据从SPI接收缓冲器(Rx Buffer)中读取出来。 4.向回调(Callback)函数发送信号,告知数据已经完成传输。 HAL SPI中断收发有很多优点,最显著的是可以解放CPU占用率。当使用轮询方式进行数据传输时,需要不断空转循环来检测SPI数据是否已经传输完成,从而浪费大量CPU时间。而使用中断服务程序,当没有SPI数据传输请求时,CPU可以处理其他任务,只有当有SPI请求时才会触发中断,大大提高了CPU的效率。此外,中断方式还可以保证数据的实时性,让数据传输更加可靠。 综上所述,HAL SPI中断收发是一种高效、可靠的SPI通信方式,通过中断服务程序可以实现实时数据传输和CPU的高效利用。在实际应用中,根据不同的需求和硬件平台,需要选择不同的SPI通信方式和中断服务程序来保证数据传输的稳定可靠。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值