OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2216|回复: 9

串口缓冲区死循环

[复制链接]

2

主题

7

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2019-1-26
在线时间
6 小时
发表于 2019-2-20 20:23:04 | 显示全部楼层 |阅读模式
1金钱
[mw_shl_code=c,true]#include "MAX232.h"

uchar USART2_TxBuffer[30];
uchar USART2_TxHeadIndex=0;
uchar USART2_TxTailIndex=0;
uchar USART2_TxBusy=0;
uchar USART2_Reserve=0;


void MAX232_USART2_Init()
{
        GPIO_InitTypeDef GPIO_InitUSART2;
        NVIC_InitTypeDef NVIC_InitUSART2;
        USART_InitTypeDef USART_InitUSART2;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
       
        USART_DeInit(USART2);
       
        GPIO_InitUSART2.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitUSART2.GPIO_Pin=GPIO_Pin_2;
        GPIO_InitUSART2.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitUSART2);
       
        GPIO_InitUSART2.GPIO_Mode=GPIO_Mode_IN_FLOATING;
        GPIO_InitUSART2.GPIO_Pin=GPIO_Pin_3;
        GPIO_Init(GPIOA,&GPIO_InitUSART2);
       
        USART_InitUSART2.USART_BaudRate=9600;
        USART_InitUSART2.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
        USART_InitUSART2.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;
        USART_InitUSART2.USART_Parity=USART_Parity_No;
        USART_InitUSART2.USART_StopBits=USART_StopBits_1;
        USART_InitUSART2.USART_WordLength=USART_WordLength_8b;
       
        NVIC_InitUSART2.NVIC_IRQChannel=USART2_IRQn;
        NVIC_InitUSART2.NVIC_IRQChannelCmd=ENABLE;
        NVIC_InitUSART2.NVIC_IRQChannelPreemptionPriority=2;
        NVIC_InitUSART2.NVIC_IRQChannelSubPriority=0;
        NVIC_Init(&NVIC_InitUSART2);
       
        USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
        USART_ITConfig(USART2,USART_IT_TC,ENABLE);
       
        USART_Init(USART2,&USART_InitUSART2);
        USART_Cmd(USART2,ENABLE);
       
        USART_GetFlagStatus(USART2, USART_FLAG_TC);
}

void USART2_SendByte(uchar Byte)
{
        while(USART2_Reserve>29);                //当缓冲区放满时程序就会在这里死循环
       
        if(USART2_TxBusy==0 && (USART2_TxHeadIndex==USART2_TxTailIndex))
        {
                USART_SendData(USART2,Byte);
                USART2_TxBusy=1;
        }
        else
        {
                USART2_TxBuffer[USART2_TxTailIndex]=Byte;
                USART2_Reserve++;
                if(++USART2_TxTailIndex>=30)
                        USART2_TxTailIndex=0;
        }
}

void USART2_IRQHandler()
{
        if(USART_GetFlagStatus(USART2,USART_FLAG_RXNE))
        {
                USART_ClearFlag(USART2,USART_FLAG_RXNE);
                printf("MAX232Õy3£ÔËDD\r\n");
        }
       
        if(USART_GetFlagStatus(USART2,USART_FLAG_TC))
        {
                USART_ClearFlag(USART2,USART_FLAG_TC);
                if(USART2_Reserve!=0)
                {
                        USART2_TxBusy=1;
                        USART_SendData(USART2,USART2_TxBuffer[USART2_TxHeadIndex]);
                        USART2_Reserve--;
                        if(++USART2_TxHeadIndex>=30)
                                USART2_TxHeadIndex=0;
                }
                USART2_TxBusy=0;
        }
}
[/mw_shl_code]

随手写的程序已贴出,大伙们帮小弟看看……

最佳答案

查看完整内容[请看2#楼]

printf这一类的函数, 是没用到DMA或中断处理的, 调用后就会在里面直到发送完成, 用是可以用, 但必须要知道它的特性才能用, 我是绝不建议在中断里用这类函数的, 就算在Main也要考虑重入的问题
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2019-2-20 20:23:05 | 显示全部楼层
printf这一类的函数, 是没用到DMA或中断处理的, 调用后就会在里面直到发送完成, 用是可以用, 但必须要知道它的特性才能用, 我是绝不建议在中断里用这类函数的, 就算在Main也要考虑重入的问题
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2019-2-20 20:38:43 | 显示全部楼层
把这一段
if(USART_GetFlagStatus(USART2,USART_FLAG_RXNE))
    {
        USART_ClearFlag(USART2,USART_FLAG_RXNE);
        printf("MAX232Õy3£ÔËDD\r\n");
    }
改为
if(USART_GetFlagStatus(USART2,USART_FLAG_RXNE))
    {
        USART2->DR;
        printf("MAX232Õy3£ÔËDD\r\n");
    }
试试
回复

使用道具 举报

1

主题

882

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3071
金钱
3071
注册时间
2018-2-7
在线时间
285 小时
发表于 2019-2-21 10:25:26 | 显示全部楼层
按照你这行代码的逻辑来看,就是死循环。while(USART2_Reserve>29);        //当缓冲区放满时程序就会在这里死循环
当USART2_Reserve=30时,30>29)为真就相当于与while(1);程序就会永远停在这
回复

使用道具 举报

2

主题

7

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2019-1-26
在线时间
6 小时
 楼主| 发表于 2019-2-21 14:32:09 | 显示全部楼层
edmund1234 发表于 2019-2-20 20:38
把这一段
if(USART_GetFlagStatus(USART2,USART_FLAG_RXNE))
    {

这次更直接了…直接死循环在中断里了……
回复

使用道具 举报

2

主题

7

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2019-1-26
在线时间
6 小时
 楼主| 发表于 2019-2-21 14:34:27 | 显示全部楼层
HXYDJ 发表于 2019-2-21 10:25
按照你这行代码的逻辑来看,就是死循环。while(USART2_Reserve>29);        //当缓冲区放满时程序就会在这 ...

亲,串口发送缓冲区中的数据后会使 USART2_Reserve 自减
回复

使用道具 举报

15

主题

866

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
7573
金钱
7573
注册时间
2016-11-30
在线时间
643 小时
发表于 2019-2-21 14:52:00 | 显示全部楼层
串口缓冲区用循环队列啊,兄嘚
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2019-2-21 15:14:33 | 显示全部楼层
LiuDY 发表于 2019-2-21 14:32
这次更直接了…直接死循环在中断里了……

这样给你说吧, 假设USART2跟打印的USART1是一样的波特率,那么就是说
你收了一个字节, 然后要发送十几个字节(USART1打印), 能在不漏掉的情况下接收所有USART2的数据?能不死循环么?
回复

使用道具 举报

2

主题

7

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2019-1-26
在线时间
6 小时
 楼主| 发表于 2019-2-21 16:29:48 | 显示全部楼层
edmund1234 发表于 2019-2-21 15:17
printf这一类的函数, 是没用到DMA或中断处理的, 调用后就会在里面直到发送完成, 用是可以用, 但必须要 ...

[mw_shl_code=c,true]int fputc(int ch, FILE *f)
{
        USART2_SendByte((uchar)ch);
  return ch;
}

void USART2_SendByte(uchar Byte)
{
        while(USART2_Reserve>29);
       
        if(USART2_TxBusy==0 && (USART2_TxHeadIndex==USART2_TxTailIndex))
        {
                USART_SendData(USART2,Byte);
                USART2_TxBusy=1;
        }
        else
        {
                USART2_TxBuffer[USART2_TxTailIndex]=Byte;
                USART2_Reserve++;
                if(++USART2_TxTailIndex>=30)
                        USART2_TxTailIndex=0;
        }
}

void USART2_IRQHandler()
{
        if(USART_GetFlagStatus(USART2,USART_FLAG_RXNE))
        {
                USART_ClearFlag(USART2,USART_FLAG_RXNE);
                 printf("MAX232Õy3£ÔËDD\r\n");
       
        }
       
        if(USART_GetFlagStatus(USART2,USART_FLAG_TC))
        {
                USART_ClearFlag(USART2,USART_FLAG_TC);
                USART2_TxBusy=0;
                if(USART2_Reserve!=0)
                {
                        USART2_TxBusy=1;
                        USART_SendData(USART2,USART2_TxBuffer[USART2_TxHeadIndex]);
                        USART2_Reserve--;
                        if(++USART2_TxHeadIndex>=30)
                                USART2_TxHeadIndex=0;
                }
        }
}[/mw_shl_code]

谢谢,问题找到了,情况是这样的…(代码贴出了printf重定向)
我把发送函数放进了USART2中断内部了,如果缓冲区满了,会循环等待缓冲区数据减少,但是这个循环在USART2中断内…所以死循环了…
现在做了个标志位,把发送函数放main里问题解决了。
回复

使用道具 举报

2

主题

7

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2019-1-26
在线时间
6 小时
 楼主| 发表于 2019-2-22 13:42:14 | 显示全部楼层
lvkanger 发表于 2019-2-21 14:52
串口缓冲区用循环队列啊,兄嘚

是循环队列啊,兄嘚
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-23 19:20

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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