找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2593|回复: 9
收起左侧

通过单片机串口通讯发送一串数据失败

[复制链接]
ID:973810 发表于 2021-10-21 14:54 | 显示全部楼层 |阅读模式
新人,学51单片机。这个问题困住了好久,解决不了,希望有大神能帮助解答一下,感谢
我想要通过串口发送一串数据,之前实验发送和接收一帧数据,都在串口中断中处理,通过STC-TSP串口助手是能够正常接收和发送的;
但是现在把发送程序从串口中断中提取出来,写成了SendByte和SendString两个函数,串口中断中接收数据后,在主函数里调用这两个函数进行发送。
但是在串口助手里,接收缓冲区一直没有数据,后来通过对比手册,觉得51单片机的全双工并不是完全的能够同时进行,所以对串口是接收还是发送也做了判断,再进行处理,这个时候发送一帧数据是可以了,可还是不能发送一串数据。
下面是我的代码
#define MAX_RECV 10
unsigned char recv_data,recv_flag,send_flag,recv_length;
unsigned char recv_buf[MAX_RECV];

void Delay_xms(unsigned char x);
void Uart_Init();
void SendByte(unsigned char dat);
void SendString(unsigned char *buf);

void main()
{
        Uart_Init();
        Delay_xms(500);
        while(1)
        {
                while(recv_flag )
                {

                        SendString(recv_buf);
                        recv_flag = 0;
                }
        }
}

void Delay_xms(unsigned char x)
{
        unsigned char y,z;
        for(y = x;y>0;y--)
                for(z=110;z>0;z--);
}

//串口初始化
void Uart_Init()
{
        TMOD = 0x20;
        SCON = 0x50;
        TH1 = 0xfd;
        TL1 = 0xfd;
        TR1 = 1;
        EA = 1;
        ES = 1;
}

//串口中断,这里以回车符作为一串数据接收完成的标志
void Uart() interrupt 4
{
        static unsigned char count = 0;  //接收帧数计数
        unsigned char temp;   //一个中间变量
        if(RI)
        {
                RI = 0;
                temp = SBUF;
                if(temp != 0x0D)     //以回车符为结束符
                {
                        recv_buf[count] = SBUF;
                        count++;
                        if(count > MAX_RECV)
                        {
                                count = MAX_RECV;
                        }
                }
                else   
                //如果接收的数据是回车符,说明一串数据接收完成,count归零
                //接收完成以后才把接收标志置1
                {
                        recv_flag = 1;     //数据接收完成标志
                        recv_length = count;
                        count = 0;
                }
        }
        if(TI)
        {
                TI = 0;
                send_flag = 0;     //send_flag:发送标志
        }
}

//发送一帧数据
void SendByte(unsigned char dat)
{
        SBUF = dat;
        send_flag = 1;
        while(send_flag);
}
//发送一串
void SendString(unsigned char *buf)
{
        while(*buf != '\0')   
        {
                SendByte(*buf);
                buf++;
        }
}

回复

使用道具 举报

ID:973810 发表于 2021-10-21 15:03 | 显示全部楼层
后面调试能通过SendByte函数发送成功也是因为问了前辈,说串口有进有出,如果不确定现在是进还是出,就会拥堵,就像堵车一样,所以我设置了recv_flag和send_flag区分,但是现在还是不能正常发送一串数据,实在不知道从哪里改了,希望有前辈能指导一下
回复

使用道具 举报

ID:94031 发表于 2021-10-21 16:37 | 显示全部楼层
小主可以学会 发表于 2021-10-21 15:03
后面调试能通过SendByte函数发送成功也是因为问了前辈,说串口有进有出,如果不确定现在是进还是出,就会拥 ...

给你改了一下,收到一串字符,同样发出去。
#include<reg51.h>

#define        UART1_BUF_LENGTH        16

unsigned char recv_data,recv_flag,send_flag,recv_length;

unsigned char        TX1_Cnt;        //发送计数
unsigned char        RX1_Cnt;        //接收计数

bit        B_TX1_Busy;        //发送忙标志

unsigned         idata RX1_Buffer[UART1_BUF_LENGTH];        //接收缓冲

void UART1_int (void) interrupt 4
{
        if(RI)
        {
                RI = 0;
                RX1_Buffer[RX1_Cnt] = SBUF;
                if(++RX1_Cnt >= UART1_BUF_LENGTH)        RX1_Cnt = 0;
        }

        if(TI)
        {
                TI = 0;
                B_TX1_Busy = 0;
        }
}

//串口初始化
void Uart_Init()
{
        TMOD = 0x20;
        SCON = 0x50;
        TH1 = 0xfd;
        TL1 = 0xfd;
        TR1 = 1;
        EA = 1;
        ES = 1;
}

void Delay_xms(unsigned char x)
{
        unsigned char y,z;
        for(y = x;y>0;y--)
                                        for(z=110;z>0;z--);
}

void main()
{
        Uart_Init();
        Delay_xms(500);
        while(1)
        {
                if((TX1_Cnt != RX1_Cnt) && (!B_TX1_Busy))        //收到数据, 发送空闲
                {
                        SBUF = RX1_Buffer[TX1_Cnt];
                        B_TX1_Busy = 1;
                        if(++TX1_Cnt >= UART1_BUF_LENGTH)        TX1_Cnt = 0;
                }
        }
}
回复

使用道具 举报

ID:123289 发表于 2021-10-21 16:41 | 显示全部楼层
【觉得51单片机的全双工并不是完全的能够同时进行】
你错了!
串口收或发一个字节的时间,CPU在此时间内可以执行几千条指令。
所以让串口同时收、发你是根本看不出来的。它们可以相差几个微秒地进行。
但是,这里强调【但是】,你的串行收、发程序,是调用了别人的程序。
如果,别人的程序必须等一帧收完,或发完后,才能执行其它的指令呢。
这样就很蠢了,浪费了大量的CPU时间。
例如发N个字符:应当是,发出一个字后,就立即转去干其它的活,直到这个字发送完成后,再回头发下一个字。收与发,是可以交叉进行的,而不是发完一帧再收一帧,或收完一帧再发一帧。
如果你是,发一个字符等发完再发下一个再等发完……,直到最后一个字符。这就太浪费时间了。
你是这样做的吗?
回复

使用道具 举报

ID:624769 发表于 2021-10-21 20:42 | 显示全部楼层
有些小习惯要一开始就不要养成。
void SendByte(unsigned char dat)
{
        SBUF = dat;
        send_flag = 1;
        while(send_flag);
}
这个习惯很不好,你这个send_flag 的作用完全没有出来,还是傻等,要这样写:
void SendByte(unsigned char dat)
{
        while(send_flag);
        SBUF = dat;
        send_flag = 1;
}
那么,这个时候你就可以做其他的事情,直道下次要再发东西的时候,才会等串口空闲。虽然在SendString的时候,意义不大,但是你想切实做到“全双工” 这点就很重要,在等待发送完成的这个时间,完全可以看看串口有没有收到新的数据,要不要处理一下之类的。
回复

使用道具 举报

ID:973810 发表于 2021-10-21 22:52 | 显示全部楼层
188610329 发表于 2021-10-21 20:42
有些小习惯要一开始就不要养成。
void SendByte(unsigned char dat)
{

谢谢,您说的这里明白了。受教
回复

使用道具 举报

ID:973810 发表于 2021-10-22 10:13 | 显示全部楼层
xuyaqi 发表于 2021-10-21 16:37
给你改了一下,收到一串字符,同样发出去。
#include

感谢!我修改并测试成功了。我还有一个问题:
测试效果我可以发送1 2 3 a b c这样的一串数据并正常接收,我发现这和之前我把接收和发送都写在串口中断里时的效果一样,可能我问题里表述不清,我其实是想要发送类似“yes,I do”这样的一句话,用您这个程序测试的话,文本模式收到的是乱码,hex模式收到的是CE CD,不明白怎么才能正确的发送。期待您的回复,万分感谢!!!
回复

使用道具 举报

ID:973810 发表于 2021-10-22 10:21 | 显示全部楼层
xuyaqi 发表于 2021-10-21 16:37
给你改了一下,收到一串字符,同样发出去。
#include

还有一个问题,在您修改后的程序下,我发送数据,比如67,有时候它接收到的就是67,但是有时候又是A7。又比如我发送 67 22 34,接收到的是 67 3
回复

使用道具 举报

ID:973810 发表于 2021-10-22 10:27 | 显示全部楼层
xuyaqi 发表于 2021-10-21 16:37
给你改了一下,收到一串字符,同样发出去。
#include

还有一个问题,在您修改后的程序下,我发送同样的数据有时接收到的数据却不一样,请问这是为什么呢。
比如我发送 67,有时候收到的是67,有时候是A7;又例如我发送67 22 34,接收的是67 3B 3C。之前自己写串口程序的时候测试也遇到了这样的问题,没有弄明白
回复

使用道具 举报

ID:94031 发表于 2021-10-22 12:02 | 显示全部楼层
小主可以学会 发表于 2021-10-22 10:13
感谢!我修改并测试成功了。我还有一个问题:
测试效果我可以发送1 2 3 a b c这样的一串数据并正常接收, ...

我能正常收发,你的波特率有问题吧。 发收.png

回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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