OpenEdv-开源电子网

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

STM32串口接收发送一组数据帧后,就不能接收数据了;只有按一下复位键后,又只能接收发送一组数据帧

[复制链接]

33

主题

99

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
309
金钱
309
注册时间
2016-5-20
在线时间
45 小时
发表于 2016-10-2 23:40:16 | 显示全部楼层 |阅读模式
10金钱
/*********************************************************************************************************
说明:1.这个程序我是拿来做485串口通讯用的,才刚刚起步就遇到了这样的问题,请高人指点,谢谢!
         2.这个程序编译都没有问题,可以直接下载到开发板,我用的是精英板
         3.程序下载到开发板后,用串口助手发数据给它,然后再返回收到的数据,串口助手发一次,它就返回一次
         4.我现在遇到的问题是:串口助手第一次发数据给它,能返回数据,并且都正确;但是再次发数据给它,就不能返回数据了
         5.据我所看到的情况就是,再次发数据给它时,它就不收数据
         6.下面附上串口助手的图片,这款串口助手软件用起来很不错,推荐给大家
         7.由于自己刚刚接触STM32,不是很熟悉,再加上C语言也不是很好,所以有劳大家了,在此一并感谢
*********************************************************************************************************/

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

void RS485_Init(void);
void ID_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 Mod_Id=0;  //用来标志作为从站的站号

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

u8 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);  //开串口接收中断使能

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



//通过GPIOF_PIN0-GPIOF_PIN3来设置1-16个站号
void ID_Init(void)
{
GPIOF ->IDR &=0X0000;
Mod_Id = GPIOF ->IDR&0x0000FFFF;
//Mod_Id = GPIO_ReadInputData(GPIOF);               
Mod_Id += 1;
}




//接收发送模式设置函数
FlagStatus RCV_SEND_Mod(u8 rcv_complete, u8 send_complete)
{
if((rcv_complete==0)||(send_complete==1))  //如果接收未完成或发送完成,则接收       
         {         
          USART_ClearITPendingBit(USART2,USART_IT_RXNE);  //清除串口接收中断标志位
          USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);  //开串口接收中断使能
          USART_ClearFlag(USART2,USART_FLAG_TC);  //清除发送完成标志位                                 
            if(send_complete==1) rcv_complete=0;
                return SET;
                }

if(rcv_complete==1)  //如果接收完成则发送       
   {                         
                send_complete=0;
                return RESET;
          }
          return RESET;
}






//接收中断函数
void USART2_IRQHandler(void)  //数据接收中断
{  
  if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收到数据
        {                 
                if(RCV_Num_Temp<64)
                {
                RCV_Buffer_Temp[RCV_Num_Temp]=USART_ReceiveData(USART2);         //读取接收到的数据
                RCV_Num_Temp++;                //接收数据增加1
                }
        }
}




//数据帧接收函数
void RS485_Receive_Data(void)
{
        u8 i;
        RCV_Num=0;       
         

if(USART_GetFlagStatus(USART2,USART_FLAG_IDLE) == SET)  //如果总线空闲,则开始接收
{
        RCV_Num=RCV_Num_Temp;        
  if(RCV_Num) LED0=0;  //接收指示
       
        delay_ms(10);                //等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
       
        if(RCV_Num==RCV_Num_Temp&&RCV_Num)//接收到了数据,且接收完成了
        {  

         for(i=0;i<RCV_Num;i++)
         {               
          RCV_Buffer[i]=RCV_Buffer_Temp[i];          
         }

          LED0=1;  delay_ms(100);       
          RCV_Num_Temp=0;  //清除数据帧字节长度缓存
         
          USART_ITConfig(USART2,USART_IT_RXNE,DISABLE);  //关串口接收中断使能
                 
    RS485_TX_EN=1;        //设置为发送模式       
          RCV_Complete=1;  //置位接收完成标志
          
   }
  }
}




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

//        while(USART_GetFlagStatus(USART2, USART_FLAG_TC) ==RESET);
        if(USART_GetFlagStatus(USART2, USART_FLAG_TC)==SET)  //判断是否发送完成
  {
         LED1=1;
         RCV_Num=0;       
       
         RS485_TX_EN=0;                        //设置为接收模式       
         SEND_Complete=1;  //置位发送完成标志

        }                       
}




//主函数
#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "beep.h"
#include "delay.h"
#include "Modbus.h"

int main(void)
{         
        u8 key;
  u8 RS485_TX_RX_ON=1;  //发送接收使能
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级

        LED_Init();                                  //初始化与LED连接的硬件接口               
        KEY_Init();                                //按键初始化       
        delay_init();                     //延时函数初始化          
        RS485_Init();        //初始化RS485
        ID_Init();
        //BEEP_Init();
                                                          
        while(1)
        {
         key=KEY_Scan(0);
       
        if(key==KEY0_PRES)   //KEY0按下,发送一次数据
        {
         delay_ms(100);
         if(key==KEY0_PRES)
         {       
                RS485_TX_RX_ON=1;
         }
        }       
               
                  
        if(RS485_TX_RX_ON==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();         
         }
         
        }
}
}








AMF`YHQVZG1XDPE2((4C15V.png

最佳答案

查看完整内容[请看2#楼]

/*************************************************************************************************************** 产生问题的原因是:接收发送模式设置函数的逻辑不对,下面附上改正后的这段程序; 另外多声明了两个全局变量 RCV_Complete_Temp SEND_Complete_Temp 用于对这段逻辑的辅助判断,这两个变量都分别在RCV_Complete SEND_Complete 的位置进行赋值; ******************************************************* ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

33

主题

99

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
309
金钱
309
注册时间
2016-5-20
在线时间
45 小时
 楼主| 发表于 2016-10-2 23:40:17 | 显示全部楼层
/***************************************************************************************************************
产生问题的原因是:接收发送模式设置函数的逻辑不对,下面附上改正后的这段程序;
另外多声明了两个全局变量 RCV_Complete_Temp    SEND_Complete_Temp 用于对这段逻辑的辅助判断,这两个变量都分别在RCV_Complete   SEND_Complete 的位置进行赋值;
***************************************************************************************************************/
//接收发送模式设置函数
FlagStatus RCV_SEND_Mod(u8 rcv_complete, u8 send_complete)
{
USART_ClearFlag(USART2,USART_FLAG_IDLE);  //清除总线空闲标志位
if((rcv_complete==0)||((RCV_Complete_Temp==0)&(send_complete==1)))  //如果接收未完成或发送完成,则接收       
         {
          USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);  //开串口接收中断使能         
          USART_ClearITPendingBit(USART2,USART_IT_RXNE);  //清除串口接收中断标志位
    USART_ClearFlag(USART2,USART_FLAG_TC);  //清除发送完成标志位       
    rcv_complete=0;  //清除接收完成标志       
                return SET;
                }

if((SEND_Complete_Temp==0)&(rcv_complete==1))  //如果接收完成则发送       
   {
    send_complete=0;  //清除发送完成标志       
                return RESET;
          }
//        return RESET;
}
回复

使用道具 举报

47

主题

212

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
292
金钱
292
注册时间
2016-1-2
在线时间
80 小时
发表于 2016-10-3 12:21:44 | 显示全部楼层
帮顶一个,同事问下,用单步调试,状态对吗?
回复

使用道具 举报

32

主题

300

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1049
金钱
1049
注册时间
2012-3-30
在线时间
321 小时
发表于 2016-10-3 12:30:29 | 显示全部楼层
寄存器标志位看看
回复

使用道具 举报

69

主题

978

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3772
金钱
3772
注册时间
2015-4-26
在线时间
765 小时
发表于 2016-10-3 12:45:25 | 显示全部楼层
串口清中断标志
我有故事,你有酒吗
回复

使用道具 举报

33

主题

99

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
309
金钱
309
注册时间
2016-5-20
在线时间
45 小时
 楼主| 发表于 2016-10-3 16:08:31 | 显示全部楼层
2938690046 发表于 2016-10-3 12:21
帮顶一个,同事问下,用单步调试,状态对吗?

软件调试不怎么熟悉,我是全靠分析逻辑,谢谢
回复

使用道具 举报

33

主题

99

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
309
金钱
309
注册时间
2016-5-20
在线时间
45 小时
 楼主| 发表于 2016-10-3 16:10:56 | 显示全部楼层
czhaii 发表于 2016-10-3 12:30
寄存器标志位看看

请问看哪个寄存器,谢谢
回复

使用道具 举报

33

主题

99

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
309
金钱
309
注册时间
2016-5-20
在线时间
45 小时
 楼主| 发表于 2016-10-3 16:15:55 | 显示全部楼层

每次都有清,应该是在中断使能的过程中清
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-25 21:13

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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