打印
[STM32F0]

讨论:串口接收数据完成标志,谢谢

[复制链接]
8374|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
cepoly|  楼主 | 2014-6-23 15:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 cepoly 于 2014-7-3 16:19 编辑

大体实现:GPS连接STM32F0单片机串口,利用中断接收,但不知道串口接收数据长度,GPS数据长度受卫星信号影响,我一直在找硬件寄存器标志,即数据接收结束后,这个寄存器标志响应,然后我就可以读个寄存器来判定数据接收完毕!

1.GPS数据长度不确定(最大可达1024个byte),如:
$GPRMC,,V,,,,,,,,,,N*53
$GPVTG,,,,,,,,,N*30
$GPGGA,,,,,,0,00,99.99,,,,,,*48
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
$GPGSV,1,1,00*79
$GPGLL,,,,,,V,N*64

我的程序如下:

void USBD_USR_Init(void)
{   
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
        
  RCC_AHBPeriphClockCmd (RCC_AHBPeriph_GPIOA,   ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
        
  GPIO_PinAFConfig(GPIOA,GPIO_PinSource9, GPIO_AF_1);
  GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1);        
  /*
  *  USART1_TX -> PA9 , USART1_RX ->;PA10
  */                                
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;                 
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);        
        
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10;               
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
  GPIO_Init(GPIOA, &GPIO_InitStructure);
        
  USART_InitStructure.USART_BaudRate   = 9600;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits   = USART_StopBits_1;
  USART_InitStructure.USART_Parity     = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode       = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USART1, &USART_InitStructure);

  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);        
  USART_ITConfig(USART1, USART_IT_TXE, DISABLE);                                                                                                
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;   
  NVIC_InitStructure.NVIC_IRQChannelPriority = 0;                 
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  USART_Cmd(USART1, ENABLE);
}

#include "usbd_cdc_core.h"
#include "stm32f0xx_tim.h"
#include "usbd_usr.h"
#include "string.h"


#define  BYTE_SIZE                          1024
#define  SEND_TO_USB                    1
#define  SEND_TO_USB_END           0

#define  CLR_REV_BYTE                   0

#define  CLR_REV_TIME                   0
#define  UART_REV_TIME                   1

USB_CORE_HANDLE  USB_Device_dev ;
typedef struct
{
  uint32_t bitrate;
  uint8_t  format;
  uint8_t  paritytype;
  uint8_t  datatype;
}LINE_CODING;
LINE_CODING serial ={9600, 0x00, 0x00,  0x08};
        
static uint8_t  RevChar[BYTE_SIZE];
static volatile uint16_t  RevSize,SendByte;;
static volatile uint8_t   rev_end;
static volatile uint8_t   rev_flag;
static volatile uint8_t   time_add;
static          uint8_t         Author[26] = "**** poly 2014.06.21 *****";  
static          uint8_t         test[5] = {5,6,7,8,9};
void Delay_us(__IO uint32_t nCount);
void Delay_ms(__IO uint32_t nCount);
void NVIC_Config(void);
void TIM2_Config(void);
void USART1_TX_DataN (uint8_t *pData,uint16_t TX_NumByte);     

int main(void)
{
        RevSize = 0;
        rev_end = 0;
        rev_flag = 0;
        NVIC_Config();
        TIM2_Config();
        memset(RevChar, '\0', BYTE_SIZE);
        USBD_Init(&USB_Device_dev, &USR_desc, &USBD_CDC_cb, &USBD_USR_Init);
  //USART1_TX_DataN (Author, 26);

  while (1)
  {        
                if((SendByte > 0) && (rev_end == SEND_TO_USB))
                {               
                        //USART1_TX_DataN (RevChar, SendByte);        
                        DCD_EP_Tx (&USB_Device_dev, CDC_IN_EP, RevChar, SendByte);                        
                        memset(RevChar, '\0', BYTE_SIZE);
                        rev_end  = SEND_TO_USB_END;
                        rev_flag = CLR_REV_TIME;

                }else{
                        if(time_add > 5)
                        {                        
                               //DCD_EP_Tx (&USB_Device_dev, CDC_CMD_EP, "a", 1);     
  //中断传输,CDC协议说是传输串口状态,论坛上坛友说用户不能用这个中断传输,目前我直接写字节传                                                                                  //输,主机HOST端也可以接收到
                                time_add = 0;
                        }
                }
        }
}

/******************************************************************************
* Function Name          : USART1_IRQHandler
* Description            : USART1
******************************************************************************/
void USART1_IRQHandler(void)
{        
        if(rev_flag == CLR_REV_TIME)
        {
                TIM_Cmd(TIM2,ENABLE);
                rev_flag = UART_REV_TIME;
        }
        
  if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
                if (serial.datatype == 7)
                {
                        RevChar[RevSize] = USART_ReceiveData(USART1) & 0x7F;
                }
                else if (serial.datatype == 8)
                {
                        RevChar[RevSize] = USART_ReceiveData(USART1);
                }
}
        
  RevSize++;
// USART_SendData(USART1,RevChar[RevSize]);

}

void TIM2_IRQHandler(void)
{
          if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)
    {
       TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);
                }

          TIM_Cmd(TIM2,DISABLE);
          rev_end  = SEND_TO_USB;        
                SendByte = RevSize;
                RevSize  = CLR_REV_BYTE;
                time_add ++;

}        
        


void Delay(__IO uint32_t nCount)
{
  /* Decrement nCount value */
  while (nCount != 0)
  {
                nCount--;
  }
}
void Delay_us(__IO uint32_t nCount)
{
  /* 10uS=>10.8uS,100uS=>104uS*/
  while (nCount != 0)
  {
                nCount--;  
                Delay(10);
  }
}
void Delay_ms(__IO uint32_t nCount)
{
  /* 10uS=>10.8uS,100uS=>104uS*/
  while (nCount != 0)
  {
                nCount--;  
                Delay(11000);
  }
}


void NVIC_Config(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        
        NVIC_Init(&NVIC_InitStructure);
}

void TIM2_Config(void)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;        
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
        TIM_DeInit(TIM2);        
        TIM_TimeBaseStructure.TIM_Period = 65536;
        TIM_TimeBaseStructure.TIM_Prescaler = 550;//n * 1.5ms
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
        TIM_ClearFlag(TIM2,TIM_FLAG_Update);
        TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
        TIM_Cmd(TIM2,DISABLE);
}

void USART1_TX_DataN(uint8_t *pData,uint16_t TX_NumByte)
{
        uint16_t i;
        for(i=0;i<TX_NumByte;i++)        
                {        
                        USART_SendData(USART1,*pData++);
//                #if(USART1_BaudRate==115200)               
//                Delay_us(90);               
//                #if(USART1_BaudRate==19200)               
//                Delay_us(500);        
//                #if(USART1_BaudRate==9600)
//                Delay_us(1000);
                        Delay_us(1000);               
                        USART_ClearFlag(USART1,USART_FLAG_TXE);
                }        
}
终于解决了数据完整帧接收,以上代码分享交流下,看看各位有没有更好的办法,继续优化
目前的办法是:中断接收GPS数据,后台开一个定时器来判断数据完整帧的结束
TIM_TimeBaseStructure.TIM_Prescaler = 150;这里会影响到数据完整帧的判断,如果开的过小,比如2ms- 100ms检查一次
我这边每一帧数据中(286 byte以上),总是会丢掉2个字节,而且丢掉的字节都相同位置的
比如完整帧如下:
$GPRMC,,V,,,,,,,,,,N*53
$GPVTG,,,,,,,,,N*30
$GPGGA,,,,,,0,00,99.99,,,,,,*48
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
$GPGSV,1,1,00*79
$GPGLL,,,,,,V,N*64

接收到的时候是:
$RMC,,V,,,,,,,,,,N*53    丢掉两个字节
$GPVTG,,,,,,,,,N*30
$GPGGA,,,,,,0,00,99.99,,,,,,*48
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
$GPGSV,1,1,00*79
$GPGLL,,,,,,V,N*64

实在找不到具体是什么原因,只能更改定时器检测时间 TIM_TimeBaseStructure.TIM_Prescaler = 150;
大概1500ms检测一次就不会丢字节,已知GPS是每秒发送一帧数据









沙发
Leeone| | 2014-6-23 17:32 | 只看该作者
意思就是接收不定长度的数据吧,这个论坛上讨论过不少方法,可以用定时器做超时判断或者用空闲中断去处理,你可以搜下

使用特权

评论回复
板凳
mmuuss586| | 2014-6-23 19:58 | 只看该作者
你可以在中断程序加个判断是否大于250,在弄个变量;
大于250个后,变量置1,主程序判断变量值;

使用特权

评论回复
地板
cepoly|  楼主 | 2014-6-23 20:14 | 只看该作者
Leeone 发表于 2014-6-23 17:32
意思就是接收不定长度的数据吧,这个论坛上讨论过不少方法,可以用定时器做超时判断或者用空闲中断去处理, ...

我先试一下  开个定时器来检测字节与字节之间的超时,看看效果

使用特权

评论回复
5
cepoly|  楼主 | 2014-6-23 20:18 | 只看该作者
mmuuss586 发表于 2014-6-23 19:58
你可以在中断程序加个判断是否大于250,在弄个变量;
大于250个后,变量置1,主程序判断变量值;
...

谢谢版主的回答
这样处理办法不是很理想,由于GPS的数据长度与卫星信号强弱有关系
250只是我估计的值,我看到论坛上说可以有中断空闲处理,但我不知道怎么应用

使用特权

评论回复
6
ar_m_cu| | 2014-6-23 22:43 | 只看该作者
为什么一定要有结束标志呢,开个缓冲区,收到数据就往里面扔。处理的时候,从缓冲区读出来处理,缓冲区有数据就可以处理。当然,一定要有结束标志的话,可以用一个定时器判断串口空闲时间,大于一定值就可以认为接收结束。

使用特权

评论回复
7
cepoly|  楼主 | 2014-7-2 19:21 | 只看该作者
ar_m_cu 发表于 2014-6-23 22:43
为什么一定要有结束标志呢,开个缓冲区,收到数据就往里面扔。处理的时候,从缓冲区读出来处理,缓冲区有数 ...

嗯  谢谢

使用特权

评论回复
8
SLHSu37| | 2014-7-3 08:33 | 只看该作者
个人感觉用IDLE中断就可以

使用特权

评论回复
9
东风小黑| | 2014-9-16 22:32 | 只看该作者
学习了

使用特权

评论回复
10
diweo| | 2014-9-17 21:50 | 只看该作者
STM32F030的USART有timeout功能的,设置RTOR寄存器,超过一定时间后就可以产生中断。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

21

主题

271

帖子

8

粉丝