搜索
bottom↓
回复: 25

串口接收8位16进制数据不会写,求教育。

[复制链接]

出0入0汤圆

发表于 2016-4-21 20:34:06 | 显示全部楼层 |阅读模式
我想写个串口接收8位,16进制数据的程序,可是完全没头绪啊,特别是到了结束位那里完全不知道怎么判断,这是网上改的程序,求我华夏前辈指点感激不尽
#include<reg52.h>
#include<intrins.h>

#define uch unsigned char
#define uint unsigned int

bit receive_flag;  //位定义,作为txdata接收到数据的标志
uch rxdata[8] = {0};                  //用于存放接收到的字符
uch txdata[8] = {0};                 //用于存放将要发送的字符
uch i = 0;

void init()                //初始化
{
        P1 = 0XFF;
        SCON = 0X50;//方式1 8位异步收发,波特率可调
        PCON = 0X80;//9600
        TMOD = 0X20;//定时器T1,方式2
        TCON= 0X40;//即TR1 = 1;开启定时T1
        TH1 = 0xfd;        //(256 - TH1 = 11059200/12/16/9600)
        TL1 = 0XFd;        //9600=2^SMOD * 晶振频率/32/12/(256 - TH1)
        EA = 1;           //总中断开启
        ES = 1;         //开启串口中断
}

void main()
{
        init();          //初始化
        while(1)
        {
                if(rxdata[0] == 0x1c)         //如果接收到的字符是1则P1口拉低
                {
                        P1 = 0X06;       
                }
                                if(rxdata[0] == 0x10)         //如果接收到的字符是1则P1口拉低
                {
                        P1 = 0Xff;       
                }
                if(receive_flag)
                {
                        SBUF = txdata[i];
                        while(!TI);        //等待数据发送完成
                        TI = 0;                //为下次发送做准备,下同
                        receive_flag = 0;
                }
        }
}

void receive() interrupt 4 using 0        //串口中断
{
        ES = 0;//防中断坑爹
        if(RI)         //等待发送
        {
                RI = 0;        //为下次发送做准备
                rxdata[i] = SBUF;        //读取数据缓冲器的值
                txdata[i] = rxdata[i];//把值移动到要发送的地址
                receive_flag = 1; // 表示接收到要发送的值
        }
        i++;
        if(i>=8)
        {
                i = 0;
        }
        ES = 1;        //开启中断
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2016-4-21 20:41:31 | 显示全部楼层
防沉自顶,改动的程序可能改的不好,求高手指教

出0入0汤圆

发表于 2016-4-21 20:43:16 来自手机 | 显示全部楼层
菜鸟你好,继续努力,帮你顶贴

出0入0汤圆

 楼主| 发表于 2016-4-21 20:52:48 | 显示全部楼层
qiqirachel 发表于 2016-4-21 20:43
菜鸟你好,继续努力,帮你顶贴

谢谢前辈

出0入12汤圆

发表于 2016-4-21 20:54:33 | 显示全部楼层
加油,你行的^_^

出0入0汤圆

发表于 2016-4-21 20:55:46 | 显示全部楼层
加油,你行的^_^

出0入0汤圆

 楼主| 发表于 2016-4-21 21:05:39 | 显示全部楼层
醉了,前辈们,真的很头疼,你们要是会就指点我一两句吧,被逗哭了

出50入8汤圆

发表于 2016-4-21 21:32:47 | 显示全部楼层
既然串口开启了中断,TI却不在中断里清零,你这程序是要中断死的节奏

出0入0汤圆

发表于 2016-4-21 21:34:18 | 显示全部楼层
LZ去学习一下状态机,接收用状态机来处理,基本思路就是第一个接收的字节判断是否是起始字节,是的话就状态机步进一步,判断第二个接受的字节。。。直到包内容收完判断结束字节,校验和。

出0入0汤圆

发表于 2016-4-21 21:38:12 | 显示全部楼层
好久没看到新手了

出0入0汤圆

发表于 2016-4-21 21:40:57 | 显示全部楼层
51的串口发送和接收是一个中断

出0入0汤圆

发表于 2016-4-21 21:51:48 | 显示全部楼层
看分坛金沙滩的小宋老师的教程,应该有你想要的

出0入8汤圆

发表于 2016-4-21 23:55:16 | 显示全部楼层
yangsen 发表于 2016-4-21 21:34
LZ去学习一下状态机,接收用状态机来处理,基本思路就是第一个接收的字节判断是否是起始字节,是的话就状态 ...

还要加上超时处理的。

出0入0汤圆

发表于 2016-4-22 00:12:43 | 显示全部楼层
可以找些视频看看,看别人讲解一下,很快就知道了。。。

出0入0汤圆

发表于 2016-4-22 00:48:09 来自手机 | 显示全部楼层
ES = 0;//防中断坑爹   挺接地气

出0入0汤圆

 楼主| 发表于 2016-4-22 10:00:42 | 显示全部楼层
kebaojun305 发表于 2016-4-21 23:55
还要加上超时处理的。

没看懂,超时处理是什么 书里没写啊,我们学校是三本,老师没讲过啊,我很笨的,求前辈不吝再点拨下

出0入0汤圆

发表于 2016-4-22 12:04:10 | 显示全部楼层
我也帮顶一下

出0入0汤圆

发表于 2016-4-22 12:18:12 | 显示全部楼层
柯铭凯 发表于 2016-4-22 10:00
没看懂,超时处理是什么 书里没写啊,我们学校是三本,老师没讲过啊,我很笨的,求前辈不吝再 ...

尽信书不如无书,超时就是你的状态机进入到某个状态后等待一段时间仍没有收到步进到下一步的信号就复位状态机或者转错误处理。贴一段原来写的收数据的程序给你参考,这个不是51的并且不是在中断中处理接收到的数据而是在主循环中检查缓冲区是否有数据要处理,有就把缓冲数据全部取出处理,你可以把判断缓冲是否空的部分去掉直接在中断中调用。我超时设的是200ms。协议帧格式是起始字+数据长度+数据+包校验+包结束字。在收到起始字后启动超时定时,定时结束前不收完所有的数据包内容就复位状态。
#define COM_OVER_TIME        200
unsigned char ucOverTime;
bool PackageStart=FALSE;
void Communication(unsigned char *ucpBuff)
{
        static unsigned char ucComState=0;
        static unsigned char ucDataLength,ucCmdAnalsys;
        unsigned char ucTemp;
        static unsigned char ucUartRd;        //uart buffer read point       
#ifdef DEBUG_SIM               
        if(PackageStart==TRUE&&ucOverTime==0)ucComState=0;                //Over time reset state
#endif       
        while(ucUartRd!=UART_RX_NUM){                //buffer not empty
                switch(ucComState){
                        case 0:                //check start
                                if(*(ucpBuff+ucUartRd)==STX){
                                        ucComState++;
                                        ucBuff[0]=STX;
                                        ucOverTime=COM_OVER_TIME;
                                        PackageStart=TRUE;
                                }
                                break;
                        case 1:                                //receive the package length
                                ucBuff[1]=*(ucpBuff+ucUartRd);
                                ucComState++;
                                ucCmdAnalsys=2;        //init the data count
                                ucDataLength=ucBuff[1];
                                break;
                        case 2:
                                if(ucBuff[1]!=ucCmdAnalsys){
                                        ucBuff[ucCmdAnalsys]=*(ucpBuff+ucUartRd);
                                        ucCmdAnalsys++;
                                        break;
                                }
                                else{                //data receive finished
                                        ucComState++;
                                        }
                        case 3:                //check BCC
                                ucTemp=BCC_PRO(ucBuff,ucDataLength);
                                if(ucTemp==*(ucpBuff+ucUartRd))
                                        ucComState=4;                //receive the package end
                                else{
                                        ucComState=0;
                                        PackageStart=0;
                                }
                                break;
                        case 4:
                                ucTemp=*(ucpBuff+ucUartRd);
                                if(ucTemp==ETX){
                                        ucBtOnlineFlag=TRUE;
                                        Command();

                                }
                                ucComState=0;
                                PackageStart=0;
                }
                ucUartRd++;                        //refresh the read counter
                ucUartRd=ucUartRd%USART_BUFF;
               
        }
}

出20入62汤圆

发表于 2016-4-22 12:28:11 | 显示全部楼层
本帖最后由 天下乌鸦一般黑 于 2016-4-22 12:33 编辑

头文件。
另一个菜鸟表示提供点思路吧,
我的这个串口可以接收一串数据,带有超时判定功能,数据格式是 :
帧头两个字节 0xf3 0xf4
命令字一个字节
数据域长度一个字节
数据域


#define g_DatRev_size  20  //接收串口中断数据的缓冲区数组大小
static unsigned int count = 0;//串口接收计数的变量
unsigned int Overtime = 2000; //2ms,超时判定2ms
unsigned char g_DatRev[g_DatRev_size]={0};//接收缓存

//-------------------串口初始化----------------------------
void init_uart()  
{  
  SCON = 0x50;   //串口方式1, 8-n-1, 允许接收.
  TMOD = 0x21;   //T1方式2 ,同时配置定时器0,工作方式1
  IP =0x10;  //把串口中断设置为最高优先级
  TH1 = 0xFD;   //9600bps@11.0592MHz
  TL1 = 0xFD;
  IE |= 0x90;
  TR1 = 1;   
  ET0=1;    //允许定时中断                  
  ES  = 1;       //开中断.
  EA  = 1;               
}

//-------------------串口中断函数---------------------------
void UART_INT(void) interrupt 4
{
   if(RI==1)  
   {
     RI = 0;       
     g_DatRev[count] = SBUF;
     if(g_DatRev[count]==0xF3&&count==0) {count=1;}//帧头
     else if(count==1 && g_DatRev[count]==0xF4) {count=2;}
     else if (count==2){Order = g_DatRev[2]        ;count=3;}
     else if (count==3){DatLgth = g_DatRev[3];count=4;}
     else if(count>=4 && count<(4+DatLgth+2)){count ++;}       
     else if(count == (DatLgth+4+2)){ES = 0; retFlag = 1;count=0;}  
     else {count=0;}
     resettimer();  
   }
   else {TI = 0;}//如果不是串口接收中断,那么必然是串口发送中断,及时清除发送中断的标志,否则一直发送中断
}

//-------------------判断count不为0的话就启动定时器-------------------------
void resettimer()
{
        TR0=0;
        TH0=(65536-Overtime)/256;
        TL0=(65536-Overtime)%256;
        if(count!=0){TR0=1;}
}

主函数main
void main (void)
{
        init_uart();
        while(1)  
        {
                if(retFlag == 1)
                {
                        //处理接收到的数据
                        retFlag = 0;
                }
        }
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2016-5-1 11:38:20 | 显示全部楼层
各位大神,我发了个新贴,把刚改好的程序发上去了,问题没执行,统共才100行代码,很简单的拉低电平而已,求大神帮忙看下问题在哪呗
#include        <reg51.h>
#define                uch        unsigned char
#define                uint        unsigned int
/*=========================================*/

bit        com_over;
bit        com_ok;
bit  T;

uch        data        com_buf[30];
uch        data        com_num=0;
uch data        send_num=0;
uch        data        com_delay;
uch data        temp[5];


void        System_init(void)       
{
        TMOD=0x21;
        SCON=0x70;//SM0=0,SM1=1,SM2=1,REN=1,TB8=0,RB8=0,TI=0,RI=0
        PCON=0x80;//波特率加倍
        TH0=0xb8;//for 11.0592 定时10MS
        TL0=0x00;
        P1 = 0X00;
        TH1=TL1=0xfa; // 9600        for 11.0592


        TR0=1;
        TR1=1;
        ET0=1;
        REN=1;
        ES=1;
        EA=1;
        com_over=0;
        com_delay=0;
        com_num=0;
}

void        main(void)
{       
        System_init();
       
       
       
        while(1)
        {        if(com_ok)
                {       
                        ES=0;
                        com_ok=0;//表明串口接受数据成功,这里先清标读
                        //这里可以加一些需要处理的子程序

                       
                       
                        //下面可以对收到的数据进行处理,这里收到的数据会通过串口发送出去,
//==================================================================================
                        //这里发送数据采用查询方式来做,
                        send_num=0;
                        do
                        {
                                temp[0]=com_buf[send_num];
                                SBUF=com_buf[send_num];//SBUF赋值后,会自动进入中断去判断有没有发送成功,
                                while(!TI);//通过TI是不是1来判断
                        TI=0;
                        send_num++;
                        }while(temp[0]!=0x0d);
                        REN=1;
                      ES=1;                       
//==================================================================================
/*                        //这里发送数据采用中断方式来做,
                        send_num=0;       
                        ES=1;        //开启串口中断               
                        SBUF=com_buf[send_num];//SBUF赋值后,会自动进入中断去判断有没有发送成功,
*/
//==================================================================================
       
                }
        }         
}       

void        timer0() interrupt 1 //定时器0中断
{

        TH0=0xb8;        //10ms,11.0592MHz
        TL0=0x00;
       
        if(com_over)
        {        com_delay++;
                if(com_delay>=3)
                {        com_delay=0x00;
                        com_over=0;
                        com_num=0;
                }
        }
}               

void        serial0() interrupt 4
{       
        if(RI)
        {        RI=0;//表示收到数据,这里先清RI
                com_over=1;com_delay=0;//开启通信超时
                com_buf[com_num]=SBUF;//把收到数据放进数组里
                if(com_buf[com_num]==0x0d) //判断是不是收到最后一个数据
                {        com_over=0;com_delay=0;//串口数据已经收完,关闭通信超时
                        com_num=0;
                        REN=0;//关闭串口接受,到主程序里面判断是否还要重新打开
                        if(com_buf[0] == 0x32)
                        {
                                if(com_buf[1] == 0x32)
                                {
                                        if(com_buf[2] == 0x39)
                                        {
                                                if(com_buf[3] == 0x36)
                                                {
                                                        if(com_buf[4] == 0x39)
                                                        {
                                                                P1 = 0xff;
                                                        }
                                                }
                                        }
                                }
                        }
                        com_ok=1;//置数据接受标志
                }
                else
                        com_num++;//不是最后一个数据,+1,方便接收下一个数据

        }               
        else if(TI)
        {        TI=0;//表示数据已经发送成功,这里先清TI
               
                if(com_buf[send_num]==0x0d) //数据是不是最后一个字节
                {        send_num=0;REN=1;//发送数据完成,开启串口接收
                }
                else
                {        send_num++;//不是最后一个字节,继续发送数据
                        SBUF=com_buf[send_num];       
                }
        }
}

出0入0汤圆

 楼主| 发表于 2016-6-16 20:25:58 | 显示全部楼层
wxdn 发表于 2016-6-10 21:15
为什么不学习MODBUS通讯的方式,后面搞两个校验的,更加好用。

大神,求教程链接

出0入0汤圆

发表于 2016-6-16 21:31:36 | 显示全部楼层
给你说个思路,如果通信协议是ascill 就检测最后的 0x0D 0x0A,如果是十六进制 就以通信速率计算两个数据的时间间隔, 每次收一个清计时器,当超过5个数据时间是认为结束。

出0入0汤圆

 楼主| 发表于 2016-6-17 12:28:16 | 显示全部楼层
snail_dongbin 发表于 2016-6-16 21:31
给你说个思路,如果通信协议是ascill 就检测最后的 0x0D 0x0A,如果是十六进制 就以通信速率计算两个数据的 ...

感觉清晰了一点,谢谢前辈

出0入0汤圆

发表于 2016-6-29 14:48:32 | 显示全部楼层
柯铭凯 发表于 2016-5-1 11:38
各位大神,我发了个新贴,把刚改好的程序发上去了,问题没执行,统共才100行代码,很简单的拉低电平而已, ...

没人原因看这么多行代码,你又是copy的,更是无人理了
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-11 18:04

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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