硬汉嵌入式论坛

 找回密码
 立即注册
查看: 820|回复: 5
收起左侧

[技术讨论] 关于使用串口缓存以及重要指令快速响应的请教

[复制链接]

4

主题

11

回帖

23

积分

新手上路

积分
23
发表于 2024-12-2 22:12:18 | 显示全部楼层 |阅读模式
本人现在使用安富莱的stm32代码模板,串口fifo体验效果极佳,将串口全部使用也无任何丢包粘包现象。现在有一个问题。就是使用串口fifo无法及时响应一些通过串口发送的重要指令(只有一两条,并且很短,比如"Stop\r\n")。
举例:在做一个小车比赛,在调试时使用了蓝牙串口模块,我们通过写一些阻塞死程序让小车走一个特定的动作。有时会出现小车走偏了,但是蓝牙是使用的串口fifo,通过安富莱模版中ReadLine这一函数读取串口信息"Stop"使小车停止的,导致蓝牙虽然将"Stop"信息发送给单片机了,但由于单片机正在执行阻塞死程序,不能及时去处理蓝牙的信息。对于安富莱的bsp_uart_fifo.c的代码修改无从下手,因为太完美了,所以想问问大家是如何使用串口实现一些重要信息快速响应的
回复

使用道具 举报

4

主题

11

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2024-12-2 22:15:28 | 显示全部楼层
/*
*********************************************************************************************************
*
*        模块名称 : 主程序入口
*        文件名称 : main.c
*        版    本 : V1.0
*        说    明 : 串口1->轮子电机,串口2->蓝牙,串口3->陀螺仪
*        修改记录 :
*                版本号      日期     作者    说明
*                V1.0    2024-11-15   Y&Z     
*
*        Copyright (C), 2015-2016, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*/

#include "bsp.h"                                /* 底层硬件驱动 */

FLAG_E ucFlag = Flag_Idle;        //标志位
STATUS_E g_ucStatus = STATUS_Idle; //运行状态
char PositionReturn[4] = {0x01, 0xFD, 0x9F, 0x6B};        //到位返回
uint8_t g_ucCarMode = 0;
uint8_t g_ucCarDir = 0;
uint32_t g_ulCarPos = 0;
uint8_t ret = 0;

/*
*********************************************************************************************************
*        函 数 名: main
*        功能说明: c程序入口
*        形    参:无
*        返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{       
        /*
                ST固件库中的启动文件已经执行了 SystemInit() 函数,该函数在 system_stm32f4xx.c 文件,主要功能是
        配置CPU系统的时钟,内部Flash访问时序,配置FSMC用于外部SRAM
        */
        bsp_Init();                /* 硬件初始化 */
        printf("\r\n\r\nBegin\r\n\r\n");
//        bsp_StartAutoTimer(2, 100);        /* 启动1个自动定时器,周期1秒 */
       
        /* 主程序大循环 */
        while (1)
        {
                bsp_Idle();                /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */

                /******************蓝牙Begin*********************/
                ret = BLUE_TOOTH_ReadLine(bluetooth_rx_buf, 50);
                if (ret)
                {
                        printf("ret %d", ret);
                        if (ret == 1)        //读取蓝牙数据,阻塞读取100ms
                        {
                                //蓝牙数据解析电机参数,并置相应标志位
                                ucFlag = BLUE_TOOTH_Parse(bluetooth_rx_buf,
                                                                                  &g_ucCarMode,
                                                                                  &g_ucCarDir,
                                                                                  &g_ulCarPos,
                                                                                  &g_ucStatus);
                        }
                        else if (ret == 2)
                        {
                                printf("Mode %d\r\nDir %d\r\nPos %d\r\n", g_ucCarMode, g_ucCarDir, g_ulCarPos);
                        }
                        ret = 0;
                }
               
                if (ucFlag != Flag_Idle)
                {
                        printf("Flag %s\r\n", NumberToFlag(ucFlag));                       
                       
                        switch (ucFlag)
                        {
                                case Flag_Stop:                /* 停止 */
                                        // 停车
                                        MOTOR_WHALE_STOP();
                                       
                                        ucFlag = Flag_Idle;
                                        break;
                               
                                case Flag_Start:         /* 以位置模式启动 */
                                        printf("Mode %d\r\nDir %d\r\nPos %d\r\n", g_ucCarMode, g_ucCarDir, g_ulCarPos);
                                        if (g_ulCarPos)       
                                        {
                                                MOTOR_WHALE_Move(g_ucCarMode, g_ucCarDir, g_ulCarPos);
                                                MOTOR_WHALE_WaitResponse(PositionReturn, 0);
                                        }
                                        printf("ok\r\n");

                                        ucFlag = Flag_Idle;
                                        break;
                               
                                case Flag_ChangeCarPar:         /* 测试 */                                       
                                        printf("Mode %d\r\n", g_ucCarMode);
                                        printf("Dir %d\r\n", g_ucCarDir);
                                        printf("Pos %d\r\n", g_ulCarPos);

                                        ucFlag = Flag_Idle;
                                        break;

                                case Flag_ChangeStatus:         /* 设置转弯后延迟 */
                                        printf("Status %s\r\n", NumberToStatus(g_ucStatus));                                       
                                        MOTOR_WHALE_Status(g_ucStatus);

                                        printf("ok\r\n");
                                        ucFlag = Flag_Idle;
                                        break;

                                case Flag_StartTest:         /* 设置转弯后延迟 */
                                        printf("StartTest00\r\n");                               
                               
                                        MOTOR_WHALE_StartTest();
                               
                                        printf("StartTest11\r\n");
                                        ucFlag = Flag_Idle;
                                        break;

                                default:
                                        break;
                        }
                }
        /******************蓝牙END*********************/
        }       
}

/***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/
回复

使用道具 举报

4

主题

11

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2024-12-2 22:15:57 | 显示全部楼层
/*
*********************************************************************************************************
*
*        模块名称 : BLUE_TOOTH 串口蓝牙模块驱动程序
*        文件名称 : bsp_bluetooth.c
*        版    本 : V1.1
*        说    明 : 封装 BLUE_TOOTH 模块相关的命令
*
*********************************************************************************************************
*/

#include "bsp.h"

/* BLUE_TOOTH 模块接线图
        BLUE_TOOTH模块    STM32-V5开发板


                UTXD   ---  PA3/USART2_RX
                GND    ---  GND
                VCC    ---  3.3V  (供电)
                URXD   ---  PA2/USART2_TX


        模块缺省波特率 460800

*/

uint8_t bluetooth_rx_buf[256] = {0};        //蓝牙接收缓存
char bluetooth_tx_buf[256] = {0};                //蓝牙发送缓存

/*
*********************************************************************************************************
*        函 数 名: bsp_InitBLUE_TOOTH
*        功能说明: 初始化二维码扫描模块的串口,  该函数被 bsp_Init() 调用。
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitBLUE_TOOTH(void)
{
        bsp_InitUart2(UART2_BAUD);       
}

/*
*********************************************************************************************************
*        函 数 名: BLUE_TOOTH_PrintRxData
*        功能说明: 打印STM32从BLUE_TOOTH收到的数据到COM3串口,主要用于跟踪调试
*        形    参: _ch : 收到的数据
*        返 回 值: 无
*********************************************************************************************************
*/
void BLUE_TOOTH_PrintRxData(uint8_t _ch)
{
        #ifdef BLUE_TOOTH_TO_COM3_EN
                comSendChar(COM3, _ch);                /* 将接收到数据打印到调试串口1 */
        #endif
}

/*
*********************************************************************************************************
*        函 数 名: BLUE_TOOTH_SendData
*        功能说明: 发送数据包
*        形    参: _databuf 数据
*                         _len 数据长度
*        返 回 值: 无
*********************************************************************************************************
*/
void BLUE_TOOTH_SendData(uint8_t *_databuf, uint16_t _len)
{
        if (_len > 2048)
        {
                _len = 2048;
        }

        comSendBuf(COM_BLUE_TOOTH, _databuf, _len);
        memset(_databuf, 0, _len);
}

/*
*********************************************************************************************************
*        函 数 名: BLUE_TOOTH_ReadLine
*        功能说明: 读取BLUE_TOOTH返回的一行应答字符串(0x0D 0x0A结束)。该函数根据字符间超时判断结束。 本函数需要紧跟AT命令发送函数。
*        形    参: _pBuf : 存放模块返回的完整字符串
*                          _usTimeOut : 命令执行超时,0表示一直等待. >0 表示超时时间,单位1ms
*        返 回 值: 0 表示错误(超时)  > 0 表示应答的数据长度
*********************************************************************************************************
*/
uint16_t BLUE_TOOTH_ReadLine(uint8_t *_pBuf, uint16_t _usTimeOut)
{
        uint8_t ucData;
        uint16_t pos = 0;
        uint16_t ret = 0;
        uint8_t hexMode = 0;  // 0: normal mode, 1: hex mode

        /* _usTimeOut == 0 表示无限等待 */
        if (_usTimeOut > 0)
        {
                bsp_StartTimer(BLUE_TOOTH_TMR_ID, _usTimeOut);                /* 使用软件定时器作为超时控制 */
        }

        while (1)
        {
                bsp_Idle();                                /* CPU空闲执行的操作, 见 bsp.c 和 bsp.h 文件 */

                if (bsp_CheckTimer(BLUE_TOOTH_TMR_ID))
                {
                        ret = 0;                /* 成功。 返回数据长度 */
                        break;
                }

                if (comGetChar(COM_BLUE_TOOTH, &ucData))
                {
                        BLUE_TOOTH_PrintRxData(ucData);                /* 将接收到数据打印到调试串口3 */

                        if (hexMode == 0)
                        {
                                if (ucData == 0xFF)
                                {
                                        hexMode = 1;  // Enter hex mode
                                        pos = 0;  // Reset buffer position
                                }
                                else if (ucData == 0x0A)  // '\n'
                                {
                                        _pBuf[pos] = 0;
                                        ret = 1;                /* 成功。 返回数据长度 */
                                        break;
                                }
                                else
                                {
                                        _pBuf[pos++] = ucData;                /* 保存接收到的数据 */
                                }
                        }

                        if (hexMode == 1)
                        {
                                _pBuf[pos] = ucData;                /* 保存接收到的数据 */
                                if (pos == 7)
                                {
                                        g_ucCarMode = _pBuf[1];
                                        g_ucCarDir = _pBuf[2];
                                        g_ulCarPos = (_pBuf[3]<<24) | (_pBuf[4]<<16) | (_pBuf[5]<<8) | (_pBuf[6]);
                                        ret = 2;                /* 成功。 返回数据长度 */
                                        break;
                                }
                                pos++;
                        }
                }
        }
        return ret;
}

/*
*********************************************************************************************************
*        函 数 名: BLUE_TOOTH_Parse
*        功能说明: 解析蓝牙数据,设置小车行驶方式,方向,距离,运行状态
*        形    参: _ParseBuf : 待解析数据
*                          _ucCarMode : 小车行驶方式
*                          _ucCarDir : 小车行驶方向
*                          _ulCarPos : 小车行驶距离
*                          _ucStatus : 小车行驶状态
*        返 回 值: _flag : 解析完成对应标志位
*********************************************************************************************************
*/
FLAG_E BLUE_TOOTH_Parse(uint8_t *_ParseBuf,
                                                uint8_t *_ucCarMode, uint8_t *_ucCarDir, uint32_t *_ulCarPos,
                                                uint8_t *_ucStatus)
{
        FLAG_E _flag;
        uint8_t* number_start;
       
        // 解析字符串
        if (strncmp((char*)_ParseBuf, "Stop", 4) == 0)
        {
                _flag = Flag_Stop;
        }
        else if (strncmp((char*)_ParseBuf, "Start", 5) == 0)
        {
                _flag = Flag_Start;
        }
        else if (strncmp((char*)_ParseBuf, "_StartTest", 9) == 0)
        {
                _flag = Flag_StartTest;
        }
        else if (strncmp((char*)_ParseBuf, "CarMode=", 8) == 0)
        {
                number_start = _ParseBuf + 8;
                *_ucCarMode = atoi((char*)number_start);
               
                _flag = Flag_ChangeCarPar;
        }
        else if (strncmp((char*)_ParseBuf, "CarDir=", 7) == 0)
        {
                uint8_t* number_start = _ParseBuf + 7;
                *_ucCarDir = atoi((char*)number_start);
               
                _flag = Flag_ChangeCarPar;
        }
        else if (strncmp((char*)_ParseBuf, "CarPos=", 7) == 0)
        {
                uint8_t* number_start = _ParseBuf + 7;
                *_ulCarPos = atoi((char*)number_start);
               
                _flag = Flag_ChangeCarPar;
        }
        else if (strncmp((char*)_ParseBuf, "Status=", 7) == 0)
        {
                uint8_t* number_start = _ParseBuf + 7;
                *_ucStatus = (atoi((char*)number_start));
                _flag = Flag_ChangeStatus;
        }       
       
        memset(_ParseBuf, 0, 256);

        return _flag;
}
/***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2024-12-3 11:20:13 | 显示全部楼层
这个时候OS就比较重要,可以有效解决这种问题。

裸机的话,也可以解决,对于裸机这种情况常用的思路就是状态机。不能一直阻塞者,导致串口的无法执行。

还有个简单易用思路,就是你这个阻塞执行的地方也加入BLUE_TOOTH_ReadLine解析。我们自己程序解决思路是阻塞的地方,会让他一直执行bsp_Idle();  在这个里面做了一些需要一直执行的功能。
回复

使用道具 举报

4

主题

11

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2024-12-3 13:00:00 来自手机 | 显示全部楼层
eric2013 发表于 2024-12-3 11:20
这个时候OS就比较重要,可以有效解决这种问题。

裸机的话,也可以解决,对于裸机这种情况常用的思路就是 ...

感谢硬汉哥的回复,恍然大悟,原来bsp_idle函数还可以用来做这种事情,感谢感谢!
回复

使用道具 举报

12

主题

41

回帖

77

积分

初级会员

积分
77
发表于 2024-12-19 10:34:00 | 显示全部楼层
eric2013 发表于 2024-12-3 11:20
这个时候OS就比较重要,可以有效解决这种问题。

裸机的话,也可以解决,对于裸机这种情况常用的思路就是 ...

还有一种思路,类似队列这样,可以吧重要的数据加入队列或者链表之类的,阻塞完再去查队列,能够保证数据被处理到,但不保证时效性
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-12 02:49 , Processed in 0.044447 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表