搜索
bottom↓
回复: 17

PIC单片机通过max485与pc通信的问题

[复制链接]

出0入0汤圆

发表于 2016-12-7 16:02:02 | 显示全部楼层 |阅读模式

实验室用的是dsPIC30f4011,刚接手没多久,现在要实现单片机通过max485和电脑通信,有一个问题是,当电脑发送5个字节以下时,通信是正常的,一旦超过5个字节单片机返回的数据就有问题,如上图所示!
求大神解答!

本帖子中包含更多资源

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

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

 楼主| 发表于 2016-12-7 16:08:46 | 显示全部楼层
本帖最后由 往事如烟 于 2016-12-7 16:16 编辑

我把代码贴出来,欢迎大神指正!谢谢了!

#include<p30f4011.h>               

_FOSC(CSW_FSCM_OFF&XT_PLL4);//4倍频晶振,Failsafe时钟关闭
_FWDT(WDT_OFF);                                //        关闭看门狗定时器
_FBORPOR(PBOR_OFF&MCLR_EN);        //掉电复位禁止,MCLR复位时能
_FGS(CODE_PROT_OFF);                //代码保护禁止
               
#define FCY  7372800               

unsigned char receive;
void delay(unsigned int z)//延时函数
{
        unsigned int x,y;
        for(x=z;x>0;x--)
          for(y=100;y>0;y--);
}


void main(void)
{        
        U1BRG=51;//波特率9600
        U1MODE=0x8420;//模式设置8位数据位,一位停止位,无奇偶校验
        U1STA=0x8400;

       TRISBbits.TRISB1=0;//设置RB1为输出状态,控制max485发送还是接收
       
          while(1)
        {
                while(U1STAbits.URXDA)//接收缓冲器有数据
                {       
                        LATBbits.LATB1=0;//控制max485状态,此时为接收状态

                        receive=U1RXREG;//max485缓存接收的数
                        delay(100);
                        
                        LATBbits.LATB1=1;//控制max485状态,此时为接收状态

                   
                           U1TXREG=receive;//max485发送数据
                           delay(100);
                           while(U1STAbits.TRMT==0);     //等待发送完毕
                            LATBbits.LATB1=0;

                }
         
     }
                  
}
   
而且一旦第一次发送超过5个字节,往后在发送5个字节以下时,还是出现错误,就和发送超过5个字节的显示一样!

出0入0汤圆

 楼主| 发表于 2016-12-7 16:21:42 | 显示全部楼层
如下图!!!

本帖子中包含更多资源

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

x

出0入0汤圆

发表于 2016-12-7 16:46:27 来自手机 | 显示全部楼层
提醒一下:485是半双工的,不能这样玩儿。接收控制脚的含义也没理解

出0入0汤圆

发表于 2016-12-7 16:53:05 | 显示全部楼层
估计是缓存满了没来得及读出来吧,用中断实现

出0入0汤圆

 楼主| 发表于 2016-12-7 16:56:51 | 显示全部楼层
砂山老妖 发表于 2016-12-7 16:46
提醒一下:485是半双工的,不能这样玩儿。接收控制脚的含义也没理解

我用一个引脚控制max485收发了呀!

出0入0汤圆

 楼主| 发表于 2016-12-7 18:23:57 | 显示全部楼层
ssaiwo 发表于 2016-12-7 16:53
估计是缓存满了没来得及读出来吧,用中断实现

本来是用中断写的!但是不知道为什么总是显示不了!后来想用这个方法,先把功能实现了!应该不是缓存满了,我定义了一个40个字节的数组缓存数据,但是发了5个字节以上的数据就出错了!

出0入0汤圆

发表于 2016-12-7 21:43:26 | 显示全部楼层
应该是数据没有接收完整就开始发送,delay函数我没有认真算,把这个参数加大试试看。这程序编的

出0入0汤圆

 楼主| 发表于 2016-12-7 21:57:34 | 显示全部楼层
本帖最后由 往事如烟 于 2016-12-7 21:59 编辑
zhuxm 发表于 2016-12-7 21:43
应该是数据没有接收完整就开始发送,delay函数我没有认真算,把这个参数加大试试看。这程序编的 ...




和延时好像没关系,上图是增大延时的结果除了慢一点,还是错!我
正在尝试在中断中接收和发送!但是不知道为什么只能发送一个字节了!源码如下!
#include<p30f4011.h>        
#include<uart.h>

_FOSC(CSW_FSCM_OFF&XT_PLL4);//4倍频晶振,Failsafe时钟关闭
_FWDT(WDT_OFF);                //    关闭看门狗定时器
_FBORPOR(PBOR_OFF&MCLR_EN);    //掉电复位禁止,MCLR复位时能
_FGS(CODE_PROT_OFF);        //代码保护禁止
        
//#define FCY  7987200
#define FCY  7372800        

unsigned char buf,buf1;
unsigned char flag_R=0;
unsigned char flag_T=0;
unsigned char len=0;


void __attribute__ ((__interrupt__)) _U1RXInterrupt(void);

void delay(unsigned int z)//延时函数
{
    unsigned int x,y;
    for(x=z;x>0;x--)
      for(y=100;y>0;y--);
}


void main(void)
{     
    U1BRG=51;
    U1MODE=0x8420;//注意,改为U1MODE=0x8020不行,为什么?
    U1STA=0x8400;
   
  //  IFS0bits.U1TXIF=0;
    IEC0bits.U1TXIE=0;
   
    IFS0bits.U1RXIF=0;
    IEC0bits.U1RXIE=1;
    TRISBbits.TRISB1=0;
   
    while(1)
    {
   
    }
}
   

void __attribute__ ((__interrupt__)) _U1RXInterrupt(void)
{
    IFS0bits.U1RXIF = 0;
    LATBbits.LATB1=0;//控制max485状态,此时为接收发送状态

    while(U1STAbits.URXDA)//读取接收到的所有数据
    {
        buf=U1RXREG;

        LATBbits.LATB1=1;
                    
        U1TXREG=buf;//max485发送数据
        delay(1000);
        while(U1STAbits.TRMT==0);

        LATBbits.LATB1=0;
    }
    flag_R=flag_R+1;
}




本帖子中包含更多资源

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

x

出0入89汤圆

发表于 2016-12-8 07:28:55 来自手机 | 显示全部楼层
楼主是刚毕业的大学生吧!

出0入0汤圆

 楼主| 发表于 2016-12-9 10:53:05 | 显示全部楼层
那个问题是什么原因不知道为什么,但是我用另外一种方法解决了这个问题,就是建立一个40字节缓存数组,在中断中接收数据,同时记录接收到的字节长!同时开启一个定时器中断,监控是否在发送数据,正在调试,下午发程序!

出0入0汤圆

 楼主| 发表于 2016-12-9 16:13:26 | 显示全部楼层
亲测可用,程序如下!
#include<p30f4011.h>               

_FOSC(CSW_FSCM_OFF&XT_PLL4);//4倍频晶振,Failsafe时钟关闭
_FWDT(WDT_OFF);                                //        关闭看门狗定时器
_FBORPOR(PBOR_OFF&MCLR_EN);        //掉电复位禁止,MCLR复位时能
_FGS(CODE_PROT_OFF);                //代码保护禁止
               

#define FCY  8000000               

unsigned char buf[40];   //定义接收数据缓存变量
unsigned char b;
unsigned char flag_R=0;//接收标志位
unsigned char len=0;//接收数据的字节长度

//函数声明
void delay(unsigned int z);
void send();
void Init();
/*******************************************************
函数名:void delay(unsigned int)
功能:延时
*******************************************************/
void delay(unsigned int z)
{
        unsigned int x,y;
        for(x=z;x>0;x--)
          for(y=100;y>0;y--);
}


/*******************************************************
函数名:void send()
功能:max485发送数据给pc
注释:b和len一样,都是接收数据的字节长,而且b在这里被清零
*******************************************************/
void send()
{
        int i;       

        for(i=0;i<b;i++)
        {
                U1TXREG=buf[i];//max485发送数据
                while(U1STAbits.TRMT==0);//等待发送完毕
        }
        b=0;
        while(U1STAbits.TRMT==0);//等待发送完毕

}
/*******************************************************
函数名:void Init()
功能:初始化以及配置
*******************************************************/
void Init()
{
        U1BRG=51;//波特率设置为9600
    U1MODE=0x8420;//模式设置,8个数据位,1个停止位,无奇偶校验
    U1STA=0x8400;//设置中断模式
   
      //  IFS0bits.U1TXIF=0;
    IEC0bits.U1TXIE=0;
   
    IFS0bits.U1RXIF=0;
    IEC0bits.U1RXIE=1;
    IPC2bits.U1RXIP=6;
       
        TRISE=0;//这两句是点亮8个灯作为是否进定时器中断的标志
        LATE=0x3f;   

    TMR1 = 0;                 //计数寄存器TMR1=0,从0开始计数
    T1CON = 0x0030;        //关闭定时器,使用内部时钟,预分频比1:256
    PR1 =0x1c20;               //周期寄存器赋值,使定时时间为1s
    IFS0bits.T1IF = 0;          //清除TMR1的中断标志
    IPC0bits.T1IP = 7;          //中断优先级为7
    IEC0bits.T1IE = 1;          //使能定时中断       
}

/***********************主函数******************************************/
void main(void)
{        
        Init();
    T1CONbits.TON=1;//开启定时器中断
   
    while(1)
        {
                delay(1000);//对于485电路这个延时不能去,232电路可以去掉,不去也不影响
                send();//发送数据
        }
}

/*********************************主函数*******************************************/

/***********************************************************************
函数名: void __attribute__ ((__interrupt__)) _U1RXInterrupt(void)
功能:串口接收中断服务函数,主要完成数据的接收以及记录接收数据的字节长
************************************************************************/
void __attribute__ ((__interrupt__)) _U1RXInterrupt(void)
{
        IFS0bits.U1RXIF = 0;//中断标志位清零

    while(U1STAbits.URXDA)//接收缓冲器有数据
    {
               buf[flag_R] =U1RXREG;
               flag_R++;
               b=flag_R;
    }
        len=b;
}

/**********************************************************************
函数名:void __attribute__((__interrupt__)) _T1Interrupt(void)
功能:1秒进一次中断,把flag_R清零,方便下次单片机接收
**********************************************************************/
void __attribute__((__interrupt__)) _T1Interrupt(void)
{   
        TMR1=0;                                                       
    IFS0bits.T1IF = 0;         //清定时器中断标志状态位

        LATE=~LATE;
       
        flag_R=0;

}

出0入0汤圆

 楼主| 发表于 2016-12-9 16:22:41 | 显示全部楼层
我后来换了一个自动485电路电路图如下!

本帖子中包含更多资源

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

x

出0入0汤圆

发表于 2016-12-9 22:06:59 | 显示全部楼层
往事如烟 发表于 2016-12-9 16:22
我后来换了一个自动485电路电路图如下!

你用这个自动转换电路,如果是波特率很高时可能会有问题,最好是自己控制,一般是需要1.5T的时间延时,根据你的串口波特率来计算1.5的时间,在发送和程序的结尾加上1.5T时间的延时就不会发生错误了,我之前做modbus协议栈时都是这样处理的。

出0入0汤圆

 楼主| 发表于 2016-12-10 18:36:01 | 显示全部楼层
zenghouyun 发表于 2016-12-9 22:06
你用这个自动转换电路,如果是波特率很高时可能会有问题,最好是自己控制,一般是需要1.5T的时间延时,根 ...

我试了你讲的那个延时,貌似太短了,那样我只能一次发一个字节,加长了延时还是只能收发5个字节以下的数据,一旦超过5个字节,就会出错!电路问题我还没考虑。我现在也在用modbus协议读写传感器,还请大神多指教呀!!!

出0入0汤圆

发表于 2016-12-11 17:27:33 | 显示全部楼层
你应该是计算错了,具体的计算方法可以网上查下,另外你要适当留点余量。

出0入0汤圆

发表于 2016-12-11 17:50:02 | 显示全部楼层
1.5T是当前波特率的1.5个字节时间,如果你延时了再切换方向肯定没有问题的。

出0入0汤圆

 楼主| 发表于 2016-12-12 16:53:15 | 显示全部楼层
zenghouyun 发表于 2016-12-11 17:50
1.5T是当前波特率的1.5个字节时间,如果你延时了再切换方向肯定没有问题的。 ...

我用的波特率是9600,传感器只接受9600或者115200,我还是用全自动收发的电路!我现在在每次接收数据时加了一个延时,就好了!和你讲的差不多!谢了!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-4-24 16:39

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

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