OpenEdv-开源电子网

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

总线空闲中断接收数据不准确

[复制链接]

33

主题

99

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
309
金钱
309
注册时间
2016-5-20
在线时间
45 小时
发表于 2016-10-19 23:15:17 | 显示全部楼层 |阅读模式
10金钱
//不用总线空闲功能,就能准确的接收数据,用了接收到的数据就会多起来,求解,谢谢
//附上串口助手监控到的数据图片


//头文件
#ifndef __MODBUS_H
#define __MODBUS_H
#include "sys.h"       

void RS485_Init(void);
void RS485_Send_Data(void);
void RS485_Receive_Data(void);

FlagStatus RCV_SEND_Mod(u8 rcv_complete, u8 send_complete);
       

extern u8 RCV_Complete;   //接收完成标志   1为完成
extern u8 SEND_Complete;   //发送完成标志   1为完成

//模式控制
#define RS485_TX_EN                PDout(7)        //485模式控制.0,接收;1,发送.

#endif





//C文件
#include "stm32f10x.h"
#include "led.h"
#include "sys.h"
#include "delay.h"
#include "Modbus.h"


u8 RCV_Complete_Temp;  //一帧接收完成缓存(1为完成)
u8 SEND_Complete_Temp;  //一帧发送完成缓存(1为完成)

u8 RCV_Complete;  //一帧接收完成(1为完成)
u8 SEND_Complete;  //一帧发送完成(1为完成)

s8 RCV_Num_Temp;  //用来表示接受到的一帧有效的字节数临时缓存(从功能码到CRC校验
u8 RCV_Num;  //用来表示接受到的一帧有效的字节数(从功能码到CRC校验)
u8 SEND_Num;  //用来表示待发送的一帧有效字节数

u8 RCV_Buffer_Temp[210];  //用来存放接收到的一帧完整的数据临时缓存(第一个字节用来存放接收到的有效字节数,也就是数组中
u8 RCV_Buffer[210];  //用来存放接收到的一帧完整的数据(第一个字节用来存放接收到的有效字节数,也就是数组中的有效字节数)
u8 SEND_Buffer[210];  //用来存放待发送的完整的一帧数据(第一个字节用来存放待发送的有效字节数,也就是数组中的有效字节数)




void RS485_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART2_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
       
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);  //使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);  //使能GPIOD时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);  //使能GPIOF时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);  //使能USART2时钟
       
USART_DeInit(USART2);
       
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;  //PD7
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
       
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;  //PA2
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;  //复用推挽
GPIO_Init(GPIOA,&GPIO_InitStructure);
       
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;  //PA3
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;  //浮空输入
GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_All;  
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;  //下拉输入
GPIO_Init(GPIOF,&GPIO_InitStructure);

RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,ENABLE);//复位串口2
RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,DISABLE);//停止复位

USART2_InitStructure.USART_BaudRate=115200;  //波特率115200
USART2_InitStructure.USART_WordLength=USART_WordLength_8b;  //数据位8位
USART2_InitStructure.USART_StopBits=USART_StopBits_1;  //停止位1位
USART2_InitStructure.USART_Parity=USART_Parity_No ;  //无校验
USART2_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;  //无硬件流
USART2_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;  //发送/接收使能
USART_Init(USART2,&USART2_InitStructure);  //初始化串口成员变量
USART_Cmd(USART2,ENABLE);  //串口使能

NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn;  //USART2全局中断
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;  //通道使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;  //抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;  //子优先级为1
NVIC_Init(&NVIC_InitStructure);  //初始化中断成员变量
USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);  //开RXNE中断使能               
USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);  //开IDLE中断使能       



RS485_TX_EN=0;  //默认为接收使能

}       






//接收发送模式设置函数
FlagStatus RCV_SEND_Mod(u8 rcv_complete, u8 send_complete)
{
FlagStatus a;

if((rcv_complete==0)||((RCV_Complete_Temp==0)&(send_complete==1)))  //如果接收未完成或发送完成,则接收       
         {         
                 
    USART_ClearFlag(USART2,USART_FLAG_TC);  //清除发送完成标志位       
    rcv_complete=0;  //清除接收完成标志       
                RS485_TX_EN=0;        //设置为接收模式
                a=SET;
                }

else if((SEND_Complete_Temp==0)&(rcv_complete==1))  //如果接收完成则发送       
    {                               
     send_complete=0;  //清除发送完成标志       
           RS485_TX_EN=1;        //设置为发送模式
                 a= RESET;
          }
         
                 return a;
}






//接收中断函数
void USART2_IRQHandler(void)  //数据接收中断
{  
u8 Clear=Clear;       
       
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //如果接收到了1个字节
        {       
               
         if(RCV_Num_Temp<64)
                {               
                 RCV_Buffer_Temp[RCV_Num_Temp++]=USART2->DR;         //读取收到的数据,清除RXNE中断
                 LED0=0;  //接收指示       
                }
               
        }
       
           if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)  //如果接收到了1帧数据
          {                       
           LED0=1;
           Clear=USART2->SR;  //读SR寄存器
     Clear=USART2->DR;  //读DR寄存器(先读SR再读DR,就是为了清除IDLE中断
                                               
           RCV_Complete_Temp=1;  //一帧接收完成临时缓存(1为完成)                               
          }       
               
}





//数据帧接收函数
void RS485_Receive_Data(void)
{
        u8 i;         
       
if(RCV_Complete_Temp==1)  //如果接收完1帧数据,则开始另存
{


        RCV_Num=RCV_Num_Temp;   
                 
        for(i=0;i<RCV_Num;i++)
        {                
         RCV_Buffer[i]=RCV_Buffer_Temp[i];        
   RCV_Buffer_Temp[i]=0X00;                         
        }
          
         RCV_Num_Temp=0;  //数据帧字节长度临时缓存设初值
         
         SEND_Complete_Temp=0;

         RCV_Complete=1;  //置位接收完成标志
         delay_ms(1);

  }
}





//数据帧发送函数
void RS485_Send_Data(void)
{
        u8 t;
       
        for(t=0;t<RCV_Num;t++)                //循环发送数据
        {       
         LED1=0;  //发送指示               
         USART_SendData(USART2,RCV_Buffer[t]);
         RCV_Buffer[t]=0X00;
   delay_ms(2);
        }       

        if(USART_GetFlagStatus(USART2, USART_FLAG_TC)==SET)  //判断是否发送完成
  {
         
         LED1=1;
         RCV_Num=0;       
               
   RCV_Complete_Temp=0;
         SEND_Complete_Temp=1;               
         SEND_Complete=1;  //置位发送完成标志
   delay_ms(1);
        }                       
}




//main()
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "Modbus.h"

int main(void)
{         

while(1)
        {

         if(RCV_SEND_Mod(RCV_Complete, SEND_Complete)==SET)
        {
          RS485_Receive_Data();         
         }                 
          


         if(RCV_SEND_Mod(RCV_Complete, SEND_Complete)==RESET)
        {
          RS485_Send_Data();         
         }

        }
}




HGDYDI{NLAERV4W(3BSGDDF.png
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165516
金钱
165516
注册时间
2010-12-1
在线时间
2116 小时
发表于 2016-10-20 21:29:57 | 显示全部楼层
你是怎么设置为总线空闲的?
回复

使用道具 举报

33

主题

99

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
309
金钱
309
注册时间
2016-5-20
在线时间
45 小时
 楼主| 发表于 2016-10-20 22:35:16 | 显示全部楼层
正点原子 发表于 2016-10-20 21:29
你是怎么设置为总线空闲的?

原子哥你好,我是这样设置的,请指点

//先在初始化函数里开使能
USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);  //开RXNE中断使能               
USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);  //开IDLE中断使能        

//然后在中断函数里做判断
//接收中断函数
void USART2_IRQHandler(void)  //数据接收中断
{  
u8 Clear=Clear;        
        
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //如果接收到了1个字节
        {        
               
         if(RCV_Num_Temp<64)
                {               
                 RCV_Buffer_Temp[RCV_Num_Temp++]=USART2->DR;         //读取收到的数据,清除RXNE中断
                 LED0=0;  //接收指示        
                }
               
        }
        
           if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)  //如果接收到了1帧数据
          {                        
           LED0=1;
           Clear=USART2->SR;  //读SR寄存器
     Clear=USART2->DR;  //读DR寄存器(先读SR再读DR,就是为了清除IDLE中断
                                                
           RCV_Complete_Temp=1;  //一帧接收完成临时缓存(1为完成)                                
          }        
               
}



//在接收函数里判断
if(RCV_Complete_Temp==1)  //如果接收完1帧数据,则开始另存
{



}
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165516
金钱
165516
注册时间
2010-12-1
在线时间
2116 小时
发表于 2016-10-23 00:49:26 | 显示全部楼层
2672751679 发表于 2016-10-20 22:35
原子哥你好,我是这样设置的,请指点

//先在初始化函数里开使能

没看明白
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-24 06:15

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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