标题: 请教单片机串口通信方面的问题,希望做过这一方面的大佬能解答一下 [打印本页]

作者: mdzzlsf    时间: 2018-4-23 15:47
标题: 请教单片机串口通信方面的问题,希望做过这一方面的大佬能解答一下
最近正在用51单片机做串口通信,已经完成了基本的发送接收。想做更深入一点:1.对接收到的数据能进行解析,比如串口助手发送了一组电压电流数据:V1012A0022,要把它还原成电压1.012伏,电路0.022A,用两数码管显示出来。
2.发送数据能不用中断吗?现在用的是interrupt 0(外部中断0),能不能不用中断,用单片机上任意的一个口控制发送。


作者: 小猫猫爱吃鱼    时间: 2018-4-23 17:28
你好!如果用任意一个口做串口发送,是可以做到的,用软件模拟串口就行。
作者: wulin    时间: 2018-4-23 19:37
你可以自定义通讯协议,比如:数据头0xff,电压整数0x01,电压小数0x0c,电流整数0x00,电流小数0x16,数据尾为有效数据和0x23,0xff 0x01 0x0c 0x00 0x16 0x23,由6组8位数据组成一个数据串,下位机收到数据串后保存在缓存中,根据数据头尾判断数据传输正确后对有效数据解析,提供给显示模块。
作者: 绪爷    时间: 2018-4-23 19:58
发数据不需要中断接收需要
作者: mdzzlsf    时间: 2018-4-24 12:11
wulin 发表于 2018-4-23 19:37
你可以自定义通讯协议,比如:数据头0xff,电压整数0x01,电压小数0x0c,电流整数0x00,电流小数0x16,数据 ...

通过状态机实现么?能否给一个大概的代码框架么,因为刚接触这方面,个人编程也不熟练,没法直接根据您提供的思路搭建出来。
作者: wulin    时间: 2018-4-24 14:41
mdzzlsf 发表于 2018-4-24 12:11
通过状态机实现么?能否给一个大概的代码框架么,因为刚接触这方面,个人编程也不熟练,没法直接根据您提 ...

没有你想的那么复杂,给你写一个示例程序参考,经TX-1C实验板与串口助手验证无误。
#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char
sbit dula=P2^6;                        //段选
sbit wela=P2^7;                        //位选
uchar code table[]={                //共阴数码管0~F、U数组
        0x3f,0x06,0x5b,0x4f,
        0x66,0x6d,0x7d,0x07,
        0x7f,0x6f,0x77,0x7c,
        0x39,0x5e,0x79,0x71,0x3e};
uchar table0[] ="OK\n";        //用于串口助手返回验证
uchar table1[]="ERROR\n";//用于串口助手返回验证
uchar rec_buf[6];                        //缓存
uint swan,wan,qian,bai,shi,ge;//数码管显示位
bit flag=0;                                        //接收完成标
/*************初始化串口**************/
void InitUART()                //9600bps@11.0592MHz
{
        PCON &= 0x7F;                //波特率不倍速
        SCON = 0x50;                //8位数据,可变波特率
        TMOD= 0x20;                        //设定定时器1为8位自动重装方式
        TL1 = 0xFD;                        //设定定时初值
        TH1 = 0xFD;                        //设定定时器重装值
        ET1 = 0;                                //禁止定时器1中断
        TR1 = 1;                                //启动定时器1
        EA = 1;                                //开总中断
        ES = 1;                                //开串口中断
}
/**********串口发送函数*************/
void SendOneByte(uchar c)
{
    SBUF = c;                //发送数据
    while(!TI);        //等待发送完成
    TI = 0;                        //发送中断请求标志位清0
}
/************数据解析函数*************/
void analysis()
{
        uchar i;                        //临时变量
        if(flag==1)                //一帧数据串接收完成
        {
                ES=0;                        //关串口中断
                flag=0;                //接收完成标志清0
                if(rec_buf[5]==rec_buf[1]+rec_buf[2]+rec_buf[3]+rec_buf[4])//验证数据和,超出8位溢出舍弃
                {
                        for(i=0;i<3;i++)
                        SendOneByte(table0);//返回OK
                }
                else
                {
                        for(i=0;i<6;i++)
                                SendOneByte(table1);//返回ERROR
                        rec_buf[0]=rec_buf[1]=rec_buf[2]=rec_buf[3]=rec_buf[4]=rec_buf[5]=0;//清除缓存数据
                }
                ES=1;                //开串口中断
        }
}
/*************数据分解***************/
void Transformation()
{
        static uint i=0;
        static bit j=0;
        i++;
        if(i==7500)                //计数延时切换显示内容
        {
                i=0;
                j=~j;
        }
        if(j==0)                        //换算电压
        {
                swan = rec_buf[1]%100/10;                        // 十万位
                wan  = rec_buf[1]%10;                                // 万位
                qian = rec_buf[2]%1000/100;                // 千位
                bai  = rec_buf[2]%100/10;                        // 百位
                shi  = rec_buf[2]%10;                                // 十位
                ge   = 16;                                                                // 个位"V"
        }
        else                        //换算电流
        {
                swan = rec_buf[3]%100/10;                        // 十万位
                wan  = rec_buf[3]%10;                                // 万位
                qian = rec_buf[4]%1000/100;                // 千位
                bai  = rec_buf[4]%100/10;                        // 百位
                shi  = rec_buf[4]%10;                                // 十位
                ge   = 10;                                                                // 个位"A"
        }
}
/**********6位数码管显示程序************/
void display()
{
        static uchar k=0;                        //分时显示变量
        switch(k)
        {
                case 0:
                   dula=0;
                   P0=table[swan];                //显示十万位段码
                   dula=1;
                   dula=0;
               
                   wela=0;
                   P0=0x7e;                                                //显示十万位码
                   wela=1;
                   wela=0;
                        k++;
                 break;       

                case 1:
                   dula=0;
                   P0=table[wan]|0x80;                //显示万位段码+小数点
                   dula=1;
                   dula=0;
               
                   wela=0;
                   P0=0x7d;                                                //显示万位位码
                   wela=1;
                   wela=0;
                        k++;
                 break;       

                case 2:
                   P0=table[qian];                        //显示千位段码
                   dula=1;
                   dula=0;
               
                   P0=0x7b;                                                //显示千位位码
                   wela=1;
                   wela=0;
                        k++;
                 break;       

                case 3:
                   P0=table[bai];                        //显示百位段码
                   dula=1;
                   dula=0;
               
                   P0=0x77;                                                //显示百位位码
                   wela=1;
                   wela=0;
                        k++;
                 break;       

                case 4:
                   P0=table[shi];                        //显示十位段码
                   dula=1;
                   dula=0;
               
                   P0=0xef;                                                //显示十位位码
                   wela=1;
                   wela=0;
                        k++;
                 break;       

                case 5:
                   P0=table[ge];                        //显示个位段码
                   dula=1;
                   dula=0;
               
                   P0=0xdf;                                                //显示个位位码
                   wela=1;
                   wela=0;
                        k=0;
                 break;       
        }
}
/**************主程序**************/
void main()
{
        InitUART();                //初始化串口
        while(1)
        {
                analysis();        //数据解析
                Transformation();//数据分解
                display();        //数码管显示
        }
}
/*********串口中断服务程序**********/
void UARTInterrupt() interrupt 4
{
        static uchar num=0;        //静态计数变量
        RI=0;                                                //接收中断请求标志位清0
        rec_buf[num]=SBUF;        //接收到的数据串保存在缓存数组
        if(rec_buf[0]==0xff)        //验证数据头(起始位)
        {
                num++;
                if(num>=6)
                {
                        flag=1;                        //接收完成标志置1
                        num=0;                        //计数变量清0
                }
        }
}
//0xff 0x01 0x0c 0x00 0x16 0x23



作者: sirf3    时间: 2018-4-24 16:16
接收要用中断,因为接收缓冲区只有一个字节,不停下手头的事去接收,SBUF会被下一个字节改变。
发送不用中断。

将发送的数据包装成一个个的数据帧,加上帧头和校验,一般还是很可靠的。
作者: mdzzlsf    时间: 2018-4-25 11:40
wulin 发表于 2018-4-24 14:41
没有你想的那么复杂,给你写一个示例程序参考,经TX-1C实验板与串口助手验证无误。
#include
#define  ...

谢谢您的解答!
作者: ttaniscy    时间: 2019-9-5 10:36
谢谢LZ分享,借鉴下
作者: dzq123    时间: 2019-9-7 20:17
绪爷 发表于 2018-4-23 19:58
发数据不需要中断接收需要

请教一下怎么发送?我每次发送数据都上位机都乱码了




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1