超时代码
//来源于STM32F4系列官方标准例程
uint8_t sFLASH_SendByte(uint8_t byte)
{
/*!< Loop while DR register in not emplty */
while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_TXE) == RESET);
/*!< Send byte through the SPI1 peripheral */
SPI_I2S_SendData(sFLASH_SPI, byte);
/*!< Wait to receive a byte */
while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_RXNE) == RESET);
/*!< Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(sFLASH_SPI);
}
//来源于STM32F1系列官方标准例程(很老的版本)
void Single_Write(unsigned char id,unsigned char write_address,unsigned char byte)
{
I2C_GenerateSTART(I2C1,ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1,id,I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1, write_address);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2C1, byte);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C1, ENABLE);
}
//来源于STM32F4系列官方标准例程
{
/* Test on I2C1 EV5 and clear it */
TimeOut = USER_TIMEOUT;
while ((!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))&&(TimeOut != 0x00))
{}
if(TimeOut == 0)
{
TimeOut_UserCallback();
}
/* Send Header to I2Cx for write or time out */
I2C_SendData(I2Cx, HEADER_ADDRESS_Write);
/* Test on I2Cx EV9 and clear it */
TimeOut = USER_TIMEOUT;
while ((!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_ADDRESS10))&&(TimeOut != 0x00))
{}
if(TimeOut == 0)
{
TimeOut_UserCallback();
}
/* Send I2Cx slave Address for write */
I2C_Send7bitAddress(I2Cx, (uint8_t)SLAVE_ADDRESS, I2C_Direction_Transmitter);
}
简要分析
首先看上面的代码,基本在时序中需要等待的部分,都是用while循环等待
第一部分SPI的等待,直接就是死等,没有超时的判断,如果硬件出了问题,那么必然卡在这里。
第二部分是以前的IIC的写法,也是一样的使用了while等时序,IIC受了干扰或者怎样,也会死在这里
第三部分是刚刚发现,竟然F4系列中IIC有了超时判读,还有超时处理?
首先是在循环等待中加了一个计数器,用来判断是否超时的。
同时又在超时时,调用了一个callback函数,来处理超时问题。
static void TimeOut_UserCallback(void)
{
/* User can add his own implementation to manage TimeOut Communication failure */
/* Block communication and all processes */
while (1)
{
}
}
这种已经算是仁至义尽了,其实也是很好的,如果出现异常,那么给回调函数去处理这个问题。
我的写法
我写的时候没想到回调函数,所以用了下面的这种需要调用者在使用函数的时候做判断。
首先是一个等待时序超时判断,如果等待时序超时了,那么有可能是一个短暂干扰,所以还可以继续尝试。
如果多次尝试失败,说明可能硬件出问题了,那么这个时候就返回传输失败的false
上层通过判断返回值,来进行异常处理,当然这种会不会出问题完全得看使用这个函数的人了。
如果他不可靠,那么这里也不可靠,就不如上面的使用回调函数,交给系统中的异常处理或者是什么其他子系统去处理这个问题。
#define GetFlag_Timeout 840
#define Transfer_Timeout 3
bool transfer (uint8_t data,*uint8_t output)
{
int timeout_T=0,timeout_W=0;
while(timeout_T++<Transfer_Timeout)
{
timeout_W=0;
while (GetFlagStatus(FLAG_TXE) == RESET && timeout_W++ < GetFlag_Timeout){}
if(timeout_W>GetFlag_Timeout)
continue;
else
break;
}
if(timeout_T>Transfer_Timeout)
return false;
SendData(data);
timeout_T=0
while(timeout_T++<Transfer_Timeout)
{
timeout_W=0;
while (GetFlagStatus(FLAG_RXNE) == RESET && timeout_W++ < GetFlag_Timeout){}
if(timeout_W>GetFlag_Timeout)
continue;
}
if(timeout_T>Transfer_Timeout)
return false;
ReceiveData(output)
return true;
}
总结
这个问题不仅仅出现在SPI,IIC这里,在其他总线里也可能会出现,涉及时序的都有可能,那么出现这种问题的时候要如何处理,就很关键了。
这种地方真的出现问题的概率其实很低,而且多半都是硬件问题,比如短路了啊,接触不良啊什么的,但是只要一出现了那么问题就非常严重了,在四轴这种东西上基本就是直接掉下来了。
我个人感觉把异常给回调函数,然后通过回调函数再去处理或者是向上抛出异常,应该是更优秀的做法。
Quote
http://blog.csdn.net/mmhh3000/article/details/41644257
FEATURED TAGS
RaspberryPi
嵌入式
Git
脚本
python
LeetCode
C++
APM
FreeRTOS
Markdown
Embedded
SD
Linux
Vim
Ubuntu
Tools
STM32
Maya
LPWAN
Graph Theory
Algorithm
PathFind
OMPL
VPS
QT
Router
JS
Chrome
Tampermonkey
API
Java
Spring
MySql
Springboot
Docker
V2ray
TTRSS
Nintendo Switch
Trace
Crack
BLHeli
DSHOT
ESC
Music
C#
EasyCon
Blog
杂谈
Proxy
UAV
GuinnessWorldRecords
NAS
群晖
ZeroTier
Typora
Map
旅游
Log
JSON
Cython
Equip
Goods
Share
DMX512
Blender
Game
AP
Network
CloudFlare
DIY
WIFI
Camera
Diablo
Sensor
SES
QQ
Bot
Python
Vmq
Jenkins
米家
ESP32
Software
C
MT793x
NXP
CH32
OpenWrt
Onion
Copilot
Cursor
Investment
ChatGPT
SFX
Debug
RouterOS
Mikrotik
GitLab
Drone
OpenAI
VS Code
管理
build
Kconfig
CMake
Su7 Ultra
Car
AI
MCP
LLM
Art
审美