【问题标题】:Loss of data from Bluetooth to UART从蓝牙到 UART 的数据丢失
【发布时间】:2014-09-28 13:11:25
【问题描述】:

我正在使用波特率为 38400 的 PIC18F87J11RN42 Bluetooth module。我制作了一个连接到蓝牙模块的安卓应用程序,并将一些数据从我的手机发送到微控制器。一切都很好,但我注意到有时我会丢失一些数据。 PIC18 预计大约 100 个字符,如果应用程序发送这 100 个字符没有问题,但有时它发送大约 98 个字符。然后 PIC18 继续等待另外 2 个字符,但下一次应用程序发送它的 100 个字符长的东西。

这导致应用程序与微控制器不同步,因为第一个字节代表一个命令。我发送的每个字符之间有大约 20 毫秒的延迟,但这并没有解决问题。这不会一直发生,但是当它发生时,一切都会变得混乱。我尝试增加似乎有帮助的时间延迟,但我不希望它太慢。

是什么导致一些数据丢失,我该如何解决?

UART代码和中断

#define CLOCK_FREQ 8000000 
#define BAUD_RATE 38400
#define SPBRG_VAL   ( ((CLOCK_FREQ/BAUD_RATE)/16) - 1)

void ConsoleInit(void)
{
 TRISCbits.TRISC7 = 1;
 TRISCbits.TRISC6 = 0;
 TXSTA = 0x24;
 RCSTA = 0x90; // 0b10010000;
 SPBRG = SPBRG_VAL;
}

BYTE ConsoleGet(void)
{
   if(RCSTAbits.OERR)
        {
        RCSTAbits.CREN = 0;   // Disable UART receiver
        RCSTAbits.CREN = 1;   // Enable UART receiver
        }

        return RCREG;
}


void timerInit (void)
{
// Time Period Achieved : 0.001s
T0CONbits.T08BIT = 0;
T0CONbits.T0CS = 0;
T0CONbits.PSA = 1;
TMR0H = 0xF8;
TMR0L = 0x30;
T0CONbits.TMR0ON = 1;
}

中断例程

if (TMR_IF) {
TMR0H = 0xF8;
TMR0L = 0x30;
  if (PIR1bits.RCIF )
           {
                ProcessMenu(); // In this function I call ConsoleGet() and have switch statment 
           }

        if (INTCONbits.TMR0IE) {
            /* there was a timer overflow */
            PIR1bits.RCIF = 0;

        }

    }

谢谢!

【问题讨论】:

  • 我在每个字符之间添加了 30 毫秒的时间延迟,目前还没有问题,但是发送 100 个字符需要更长的时间。我需要发送更多大约 1000 条消息,每条消息长度为 100 个字符。这个过程需要30多分钟,非常长。如何在不丢失数据的情况下减少时间延迟?我需要提高波特率吗?
  • 我把波特率提高到500k看看会不会更好,没有效果,没有30ms的延时我还是丢数据。我很困惑!
  • 请考虑添加 UART 初始化代码,您从 UART 例程接收的中断例程?没有代码,有很多地方可能出错。
  • @Jean-francois:我添加了代码,如果您需要其他任何内容,请告诉我,谢谢!

标签: android bluetooth embedded microcontroller pic


【解决方案1】:

当接收程序丢失通过 UART 接收到的字节时,通常意味着接收程序没有足够快地为 UART 的接收中断提供服务。 UART 只能保存有限数量的接收字节,可能只有一个。因此,您的程序必须在 UART 接收下一个字节之前从 UART 中读取接收到的字节。如果您在下一个字节到达之前没有从 UART 读取字符,那么 UART 将丢弃一个字节,您的程序将丢失它。

如果您使用 ISR 来处理 UART 的接收中断,那么我可以想到两个可能的原因,即您的程序可能无法足够快地处理中断。一个原因是程序可能会花费太多时间来处理更高优先级的中断。那么较低优先级的 UART 接收中断可能会被延迟太久,并且 UART 会丢弃字节。您是否有执行数毫秒的更高优先级 ISR?

第二个原因是您的程序可能在接收中断本身上花费了太多时间。您的 ISR 调用 ProcessMenu() 这似乎很可疑。如果 ProcessMenu() 进行了大量处理并且花费的时间超过了串行接口的字符间延迟,那么您的程序将无法足够快地处理接收中断,并且 UART 将丢弃字节。 ProcessMenu()的最大执行时间是多少?

这些原因是为什么存在保持 ISR 简短的一般经验法则的两个例子。

如果 ProcessMenu() 确实花费了太长时间,那么解决方法是,不要从 ISR 中调用 ProcessMenu()。 ISR 应该简单地从 UART 读取字节并将其复制到 RAM 中的循环接收缓冲区。这样 ISR 会很快完成,并在 UART 接收另一个字节之前再次准备好。然后,在 ISR 之外,主编程循环应该轮询接收缓冲区并在有可用字节时调用 ProcessMenu()。

【讨论】:

  • 你的回答很有道理,+1。在我不使用 UART 中断之前,我只是在 while 循环上扫描 PIR1bits.RC1IF,现在我确实使用了 UART 中断,但确实 ProcessMenu() 需要很长时间才能完成。我会尝试你的建议,看看能把我引向何方。
【解决方案2】:

PIC18F87J11 有 2 个不同的 UART 模块,UART1 和 UART2。在写入寄存器时,您必须指定您使用的是哪一个。你也不用 BAUDCON 来指定波特率值是 8 位还是 16 位,

TXSTA1 = 0b00100100; // TXEN, BRGH
RCSTA1 = 0b10010000; // SPEN, CREN (ASYNC assume)
BAUDCON1 = 0b00000000; //8 bit baudrate at 38400.
SPBRGL = .12;         //ecimal value for 38400 BS, 0.16% error

这是用于 UART1 初始化的。输入/输出由 uart 模块直接驱动,如数据表中所述 EUSARTx 控制将自动 将引脚从输入重新配置为输出 需要。

然后,在你的中断程序中,你搞砸了一些事情,假设你已经设置了必要的位:

PIE.RC1IE = 1; //Enable receive interrupt IPEN = 0; //All masked interrupt enabled GIE = 1; // PEIE = 1; //Enable peripheral interrupts (RC1IE)

然后,在中断例程的括号内

   INTCON.GIE = 0;   //Disable all interrupts
   //Series of IF to gather interrupt source
   if (PIR1.RC1IF)    //Receive serial flag up?
    {
      if (ucTrackBuffer >= BufferSize){ucTrackBuffer= 0;}
      //if ucTrackBuffer >= BufferSize, reset 0.
      ucTabRx232[ucIndiceTampon] = RCREG1;//Receive uart to buffer
      ucTrackBuffer++;                    //increm buffer tracking
    }
   INTCON.GIE = 1;               //Re-start interrupts
   PIR1.RCIF = 0;                //Lower flag to permit a second interrupt

所有这些代码都可以帮助你。注意 ISR 中的括号,并且永远不要在 ISR 中调用函数,因为您可能会跳过宝贵的指令周期(跳过一个字符!)。

中断服务

if (PIR1.RC1IF)
 {
   //Code for serial reception
 }
if (TMR1_IF)
 { 
   //Code for timer1 overflow
 }

希望对您有所帮助,如果您需要其他任何东西,请告诉我。

【讨论】:

  • 奇怪的是,这一切都没有帮助解决问题,甚至没有让问题变得更好。 UART 不中断的唯一方法是在 Android 应用程序上发送的每个字符之间添加 30 毫秒的时间延迟。至此,不知道是Micro还是APP造成了这个问题,希望大家支持+1。
  • 你有没有按照我说的从定时器中断例程中删除接收中断例程并把它们分开?如果你没有,也许RX中断只有在定时器溢出时才赶上。
  • 我试过了,但我没有看到任何改进,仍然有问题。
  • 至少用示波器、逻辑分析仪甚至 PC uart 确定波特率是否良好,尝试从 PIC 向 PC 发送任何字符(这样我们就可以确保 UART 正确初始化)
  • 我知道波特率很好,因为我可以从 UART 写入和获取字符。我唯一的问题是,当我从我的 android 应用程序发送字符时,PIC 有时没有接收到这些字符。
猜你喜欢
  • 2020-12-27
  • 2015-08-08
  • 2014-03-05
  • 2016-12-20
  • 1970-01-01
  • 2014-10-24
  • 1970-01-01
  • 1970-01-01
  • 2017-06-16
相关资源
最近更新 更多