硬汉嵌入式论坛

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

[UART] 裸机下获取USART串口数据容易卡死 ??

[复制链接]

610

主题

3060

回帖

4910

积分

至尊会员

积分
4910
发表于 2019-5-17 09:40:25 | 显示全部楼层 |阅读模式
裸机下获取USART串口数据容易卡死 ??

具体如下:

裸机情况下,貌似使用 UART1_GetCharEx 这个函数获取数据时,每次最大不能够超过 20 byte,如果超过 程序卡死,另外 获取的数据后,貌似需要等一会后 才可以继续获取数据,这是怎么回事啊 ???

typedef struct
{
        uint8_t *pRxBuf;                        /* 接收缓冲区 */
        uint16_t usRxBufSize;                /* 接收缓冲区大小 */

        uint16_t usRxWrite;                        /* 接收缓冲区写指针 */
        uint16_t usRxRead;                        /* 接收缓冲区读指针 */
        uint16_t usRxCount;                        /* 还未读取的新数据个数 */
} _UART1_T;


_UART1_T  g_tUART1;


/*
*********************************************************************************************************
*        函 数 名: UART1_UartVarInit
*        功能说明: 初始化串口相关的变量
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
static void UART1_UartVarInit(void)
{
        g_tUART1.pRxBuf = g_Uart1RxBuf;                                        /* 接收缓冲区指针 */
        g_tUART1.usRxBufSize = UART1_RX_BUF_SIZE;        /* 接收缓冲区大小 */
        g_tUART1.usRxWrite = 0;                                                /* 接收FIFO写索引 */
        g_tUART1.usRxRead = 0;                                                /* 接收FIFO读索引 */
        g_tUART1.usRxCount = 0;                                                /* 接收到的新数据个数 */
}


#define UART1_RX_BUF_SIZE          1*1024
  __attribute__((section (".RAM_D4"))) uint8_t g_Uart1RxBuf[UART1_RX_BUF_SIZE];                /* 接收缓冲区 */





/*
*****************************************************************************
* 在usart 中断 中调用
*****************************************************************************
*/
void  UART1_DataRx(u8 buffer)
{       
        g_tUART1.pRxBuf[g_tUART1.usRxWrite] = buffer;
        if (++g_tUART1.usRxWrite >= g_tUART1.usRxBufSize)
        {
                g_tUART1.usRxWrite = 0;
        }
        if (g_tUART1.usRxCount < g_tUART1.usRxBufSize)
        {
                g_tUART1.usRxCount++;
        }
}



/*
*********************************************************************************************************
*        函 数 名: UartIRQ
*        功能说明: 供中断服务程序调用,通用串口中断处理函数
*        形    参: _pUart : 串口设备,如USART1,USART2,UART3,UART7 ... ...
*        返 回 值: 无
*********************************************************************************************************
*/
static void UartIRQ(USART_TypeDef *_pUart)
{
        uint32_t isrflags   = READ_REG(_pUart->ISR);
        uint32_t cr1its     = READ_REG(_pUart->CR1);
        uint32_t cr3its     = READ_REG(_pUart->CR3);
       
        if(_pUart == USART1)
        {
                /* 处理接收中断  */
                if ((isrflags & USART_ISR_RXNE) != RESET)
                {
                        /* 从串口接收数据寄存器读取数据存放到接收FIFO */
                        uint8_t ch;

                        ch = READ_REG(_pUart->RDR);
                        UART1_DataRx( ch );
                }
        }
       
        /* 清除中断标志 */
        SET_BIT(_pUart->ICR, UART_CLEAR_PEF);
        SET_BIT(_pUart->ICR, UART_CLEAR_FEF);
        SET_BIT(_pUart->ICR, UART_CLEAR_NEF);
        SET_BIT(_pUart->ICR, UART_CLEAR_OREF);
        SET_BIT(_pUart->ICR, UART_CLEAR_IDLEF);
        SET_BIT(_pUart->ICR, UART_CLEAR_TCF);
        SET_BIT(_pUart->ICR, UART_CLEAR_LBDF);
        SET_BIT(_pUart->ICR, UART_CLEAR_CTSF);
        SET_BIT(_pUart->ICR, UART_CLEAR_CMF);
        SET_BIT(_pUart->ICR, UART_CLEAR_WUF);
        SET_BIT(_pUart->ICR, UART_CLEAR_TXFECF);
}



/*
*********************************************************************************************************
*        函 数 名: UART1_UartGetChar
*        功能说明: 从串口接收缓冲区读取1字节数据 (用于主程序调用)
*        形    参: _pUart : 串口设备
*                          _pByte : 存放读取数据的指针
*        返 回 值: 0 表示无数据  1表示读取到数据
*********************************************************************************************************
*/
static uint8_t UART1_UartGetChar(_UART1_T *_pUart, uint8_t *_pByte)
{
        uint16_t usCount;

        /* usRxWrite 变量在中断函数中被改写,主程序读取该变量时,必须进行临界区保护 */
        DISABLE_INT();
        usCount = _pUart->usRxCount;
        ENABLE_INT();

        /* 如果读和写索引相同,则返回0 */
        //if (_pUart->usRxRead == usRxWrite)
        if (usCount == 0)        /* 已经没有数据 */
        {
                return 0;
        }
        else
        {
                *_pByte = _pUart->pRxBuf[_pUart->usRxRead];                /* 从串口接收FIFO取1个数据 */

                /* 改写FIFO读索引 */
                DISABLE_INT();
                if (++_pUart->usRxRead >= _pUart->usRxBufSize)
                {
                        _pUart->usRxRead = 0;
                }
                _pUart->usRxCount--;
                ENABLE_INT();
                return 1;
        }
}



/*
uart1 串口接收函数,放在主程序里面不停的调用
*/
uint8_t UART1_GetCharEx(void)
{
        uint8_t ucData;
  uint8_t temp = 0;
//uint16_t usPos = 0;

        /* 从 UART1 模块串口读取1个字节 */
        while (1)
        {
                if (UART1_UartGetChar(&g_tUART1, &ucData))
                {
                        #if  1
                                /* 将收到的 模块数据按原样 打印到COM1 口,便于跟踪调试 */
                       
                        /* 写一个字节到USART1 */
                        USART1->TDR = ucData;
                        /* 等待发送结束 */
                        while((USART1->ISR & USART_ISR_TC) == 0)
                        {}
                               
                        #else  //把接收到的数据拷贝备份,供后续其他程序处理
                               
                        {
                                if (usPos < sizeof(g_Uart1RxBufBak))
                                {
                                        g_Uart1RxBufBak[usPos++] = ucData;
                                }
                                else
                                        usPos =0;
                       
                        }

                        #endif
                               
                                continue;        /* 可能还有数据,继续分析 */
                }

                        break;        /* 没有接收到数据,退出函数 */
        }
       
        return temp;
}



void USART1_IRQHandler(void)
{
        UartIRQ(USART1);
}




int main(void)
{
  .. ...

  while(1)
  {
    UART1_GetCharEx();
  }

}


上述程序,搞到 带 os 系统的工程里面,貌似工作非常正常,获取接收数据也是完全对的,单次数据量超过 32 byte 也不会卡死








回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2019-5-17 10:59:22 | 显示全部楼层
可以直接使用我们的H7驱动bsp_uart_fifo.C,你这个貌似是我们的改造版。
回复

使用道具 举报

610

主题

3060

回帖

4910

积分

至尊会员

积分
4910
 楼主| 发表于 2019-5-17 12:31:14 | 显示全部楼层
eric2013 发表于 2019-5-17 10:59
可以直接使用我们的H7驱动bsp_uart_fifo.C,你这个貌似是我们的改造版。

是的,这个就是 参考你们的 h7 修改的
回复

使用道具 举报

20

主题

114

回帖

174

积分

初级会员

积分
174
发表于 2019-5-17 12:41:22 | 显示全部楼层
去掉DISABLE_INT()和ENABLE_INT()试试
回复

使用道具 举报

610

主题

3060

回帖

4910

积分

至尊会员

积分
4910
 楼主| 发表于 2019-5-17 16:20:52 | 显示全部楼层
magicoctoier 发表于 2019-5-17 12:41
去掉DISABLE_INT()和ENABLE_INT()试试

去掉了貌似也不行,

搞不懂怎么搞到带 os 系统的 工程里面是没有问题的,通用的 这个 usart1 程序,而且这个里面也没有使用 dma ,应该也不会牵扯到 dma 的事情吧 ???
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2019-5-17 16:42:47 | 显示全部楼层
hpdell 发表于 2019-5-17 12:31
是的,这个就是 参考你们的 h7 修改的

直接使用我们的先测试,整稳定了,再修改成你的
回复

使用道具 举报

610

主题

3060

回帖

4910

积分

至尊会员

积分
4910
 楼主| 发表于 2019-5-17 17:17:19 | 显示全部楼层
本帖最后由 hpdell 于 2019-5-17 17:19 编辑
eric2013 发表于 2019-5-17 16:42
直接使用我们的先测试,整稳定了,再修改成你的

这套程序 使用在 gps 上 或者是 带 os 系统 的工程上是完全没有问题的,
如果裸机单独使用这个程序就不行,有些疑惑啊 ??
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2019-5-17 17:25:12 | 显示全部楼层
hpdell 发表于 2019-5-17 17:17
这套程序 使用在 gps 上 或者是 带 os 系统 的工程上是完全没有问题的,
如果裸机单独使用这个程序就不 ...

这种可以排查,直接在你的OS工程里面将main函数里面所有函数注释掉,注意必须是你的RTOS带串口工程,然后测试串口是否正常
回复

使用道具 举报

610

主题

3060

回帖

4910

积分

至尊会员

积分
4910
 楼主| 发表于 2019-5-17 20:22:05 | 显示全部楼层
本帖最后由 hpdell 于 2019-5-17 21:10 编辑
eric2013 发表于 2019-5-17 17:25
这种可以排查,直接在你的OS工程里面将main函数里面所有函数注释掉,注意必须是你的RTOS带串口工程,然后 ...

貌似找到问题所在了,

原因是在裸机情况下,程序运行的比较快,当主程序去获取 数据时,此时串口正在接收数据,而此时获取数据时关闭了中断,导致接收错误造成的吧 ?

我目前在主程序里面增加了 延时 20ms ,貌似现在接收数据及长度没有限制了.
貌似是在获取数据时,平凡的 进行开关中断,不知道还有没有其他更好的办法能够知道 是没有数据接收或者是接收超时了啊 ??
回复

使用道具 举报

610

主题

3060

回帖

4910

积分

至尊会员

积分
4910
 楼主| 发表于 2019-5-17 22:49:36 | 显示全部楼层
程序我 改了一下, 现在貌似可以了,只是判断 接收 '\r' || '\n' 即可

/*
*****************************************************************************
* 在usart 中断 中调用
*****************************************************************************
*/
void  UART1_DataRx(u8 buffer)
{       
        g_tUART1.pRxBuf[g_tUART1.usRxWrite] = buffer;
        if (++g_tUART1.usRxWrite >= g_tUART1.usRxBufSize)
        {
                g_tUART1.usRxWrite = 0;
        }
        if (g_tUART1.usRxCount < g_tUART1.usRxBufSize)
        {
                g_tUART1.usRxCount++;
        }
        if((buffer == '\r') || (buffer == '\n'))  //结束符,说明接收完成
        {
                g_tUART1.RxEnd = 1;
        }
}



static void UART1_UartVarInit(void)
{
        g_tUART1.pRxBuf = g_Uart1RxBuf;                                        /* 接收缓冲区指针 */
        g_tUART1.usRxBufSize = UART1_RX_BUF_SIZE;        /* 接收缓冲区大小 */
        g_tUART1.usRxWrite = 0;                                                /* 接收FIFO写索引 */
        g_tUART1.usRxRead = 0;                                                /* 接收FIFO读索引 */
        g_tUART1.usRxCount = 0;                                                /* 接收到的新数据个数 */
        g_tUART1.RxEnd  = 0;  //
}


/*
*********************************************************************************************************
*        函 数 名: UART1_UartGetChar
*        功能说明: 从串口接收缓冲区读取1字节数据 (用于主程序调用),这个函数里面的中断也可以取消不用了
*        形    参: _pUart : 串口设备
*                          _pByte : 存放读取数据的指针
*        返 回 值: 0 表示无数据  1表示读取到数据
*********************************************************************************************************
*/
static uint8_t UART1_UartGetChar(_UART1_T *_pUart, uint8_t *_pByte)
{
        uint16_t usCount;

        /* usRxWrite 变量在中断函数中被改写,主程序读取该变量时,必须进行临界区保护 */
        usCount = _pUart->usRxCount;

        /* 如果读和写索引相同,则返回0 */
        //if (_pUart->usRxRead == usRxWrite)
        if (usCount == 0)        /* 已经没有数据 */
        {
                return 0;
        }
        else
        {
                *_pByte = _pUart->pRxBuf[_pUart->usRxRead];                /* 从串口接收FIFO取1个数据 */

                /* 改写FIFO读索引 */
                if (++_pUart->usRxRead >= _pUart->usRxBufSize)
                {
                        _pUart->usRxRead = 0;
                }
                _pUart->usRxCount--;
                return 1;
        }
}


/*
uart1 串口接收函数,放在主程序里面不停的调用
*/
uint8_t UART1_GetCharEx(void)
{
        uint8_t ucData;
  uint8_t temp = 0;
//uint16_t usPos = 0;
               
        if(g_tUART1.RxEnd)
        {
                g_tUART1.RxEnd =0;
                while(1)
                {
                        if (UART1_UartGetChar(&g_tUART1, &ucData))
                        {
                                #if  1
                                        /* 将收到的 模块数据按原样 打印到COM1 口,便于跟踪调试 */
                               
                                /* 写一个字节到USART1 */
                                USART1->TDR = ucData;
                                /* 等待发送结束 */
                                while((USART1->ISR & USART_ISR_TC) == 0)
                                {}
                                       
                                #else  //把接收到的数据拷贝备份,供后续其他程序处理
                                       
                                {
                                        if (usPos < UART1_RX_BAK_BUF_SIZE)
                                        {
                                                g_Uart1RxBufBak[usPos++] = ucData;
                                        }
                                        else
                                                usPos =0;
                                }
                                #endif

                                continue;        /* 可能还有数据,继续分析 */
                        }
                        break;
                }
        }
               
        return temp;
}





回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2019-5-18 01:28:55 | 显示全部楼层
hpdell 发表于 2019-5-17 22:49
程序我 改了一下, 现在貌似可以了,只是判断 接收 '\r' || '\n' 即可

/*

谢谢告知最终解决办法。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-10 18:05 , Processed in 0.329188 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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