This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP430F249:3019066632

Guru**** 2386970 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1203673/msp430f249-3019066632

器件型号:MSP430F249

大家好!

我正在使用以下初始化、但仍然收到错误:

UCA0CTL0 |= 0x00;//无奇偶校验、LSB 优先、8位字符、1个停止位、UART 模式、异步模式
UCA0CTL1 |= 0x40;// ACLK
UCA0CTL1 |= UCSWRST;//禁用 UART。
UCA0MCTL |= UCBRF_4 + UCBRS_7 + UCOS16;// 230、400波特。
// UCA0MCTL |= UCBRF_3 + UCBRS_5 + UCOS16;// 230,400波特(原始)。
UCA0BR0 |= 0x05;//波特率高字节预分频器,230,400波特。
UCA0BR1 |= 0x00;//波特率预分频的低字节。

UCA0CTL1 &=~UCSWRST;//启用 UART。

ACLK 为16MHz、看上去稳定而干净。

我已经尝试了各种  UCA0MCTL 值、但找不到 能够正确地从传入 RX 收集数据的组合。 注释掉的行以前可以使用、但现在不再使用。

请告知。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    会出现什么错误? 偶尔会出现位错误? 错过的字符? 或完全没有响应。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    显示读取接收寄存器的代码。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

     UCA0STAT 寄存器中的所有三个错误位都被一致置位、并且 UCA1RXBUF 通常包含一个0x5F。 传入数据包标头(第一个字节)为0x5A、但从未检测到。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    //& UART 读
    //
    //将数据包从 UART 读取到 Upstone_Data[]数组中。
    //
    ************二○○一年;***
    开关(Serial_Rd_State)//***** UART 读取数据包状态机开始*****

    案例 Ser_Rd_Start://等待主机发送数据包标头。
    if (UCA0RXIFG ==( UCA0RXIFG & IFG2 )){
    P3OUT &&~Ω LED1n;//打开 LED
    packet_Header = UCA0RXBUF;//从串行端口读取一个字节。
    IFG2 &=~UCA0RXIFG;
    CmpChecksum = Packet_Header;//初始化校验和。
    System_Flags |= UART_RX_BUSY;//设置 BUSY 标志。
    UART_TIMER = 0;//复位计时器

    if ( Packet_Header == 0X5A ){//如果数据包标头已被接收,那么...
    Upstep_pointer = 0;//...initialize 数组索引、并且……
    Upstone_Data[Upstone_pointer]= Packet_Header;//将数据写入缓冲存储器。
    上游_指针++;

    serial_Rd_State = ser_Rd_Cmd;//...收集数据包的其余部分。
    }
    P3OUT |= LED1n;//关闭 LED
    }
    中断;

    案例 Ser_Rd_Cmd://等待主机发送数据包标头。
    if (UCA0RXIFG ==( UCA0RXIFG & IFG2 )){
    packet_Command = UCA0RXBUF;//从串行端口读取下一个字节。
    IFG2 &=~UCA0RXIFG;

    Serial_Port_Data = Packet_Command;//解析命令。
    Upstone_Data[Upstone_pointer]= Packet_Command;//将数据写入缓冲存储器。
    上游_指针++;
    CmpChecksum += Packet_Command;//将下一个字节添加到校验和中。

    Serial_Rd_State = Ser_Rd_BNum;
    }
    中断;

    Case Ser_Rd_BNum://
    if (UCA0RXIFG ==( UCA0RXIFG & IFG2 )){
    BRICK_Num = UCA0RXBUF;//从串行端口读取下一个字节。
    IFG2 &=~UCA0RXIFG;

    Upstone_Data[Upstone_pointer]= Brick_Num;//将数据写入缓冲存储器。
    上游_指针++;
    CmpChecksum += Brick_Num;//将下一个字节添加到校验和中。

    if ( Brick_Num >5 ){ Serial_Rd_State = Ser_Rd_CSUM;}

    else if ( Packet_Command == 0x42 ){
    System_Flags |= DNSTREAM_TX_START;//开始下一个传输到主器件。

    Serial_Rd_State = Ser_Rd_Data;
    }

    否则{
    ERROR_COUNTA++;
    Serial_Rd_State = Ser_Rd_Start;
    }
    }
    中断;

    案例 Ser_Rd_Data://
    if (UCA0RXIFG ==( UCA0RXIFG & IFG2 )){
    Upstown_Data[Upstone_pointer]= UCA0RXBUF;//将数据写入缓冲存储器。
    IFG2 &=~UCA0RXIFG;

    CmpChecksum +=上游_Data[上游_Pointer];//将下一个字节添加到校验和中。
    上游_指针++;

    if ( Upstone_pointer >= Rx_Packet_Length -1 ){ Serial_Rd_State = Ser_Rd_CSUM;}
    }
    中断;

    案例 Ser_Rd_CSUM://
    if (UCA0RXIFG ==( UCA0RXIFG & IFG2 )){
    PktChecksum = UCA0RXBUF;//从串行端口读取下一个字节。
    IFG2 &=~UCA0RXIFG;

    Upq_Data[Upstep_pointer]= PktChecksum;//将数据写入缓冲存储器。
    上游_指针++;
    packet_Count++;
    System_Flags &&~UART_RX_BUSY;//清除 BUSY 标志。
    System_Flags |= NEW_PKT_RDY;//设置新数据包标志。

    // if ( PktChecksum != CmpChecksum ){
    // P3OUT &&~Ω LED0n;//打开 LED。 五颗星 测试代码! 五颗星
    // P3OUT |= LED0n;//关闭 LED。 五颗星 测试代码! 五颗星
    //}

    Serial_Rd_State = Ser_Rd_Start;
    }
    中断;

    案例 Ser_Rd_Timeout://重置 UART 并重新启动状态机
    UCA0CTL1 |= UCSWRST;//禁用 UART。
    System_Flags &&~UART_RX_BUSY;//清除 BUSY 标志。
    Serial_Rd_State = Ser_Rd_Start;
    UCA0CTL1 &=~UCSWRST;//启用 UART。
    中断;

    }//***** UART 读取数据包状态机的末尾*****

    }//字节 Brick_Col 为== zero。


    if ( Brick_Col >0 ){
    //上游读:*****
    //
    //将数据包从上行端口读入上游数据[]数组。
    //
    //绩效指标问题

    switch (upline_Pkt_Rd_State)//***** 上行数据包读取状态机开始*****

    案例 Upstr_Read_Start://如果上行端口有数据,则启动读取状态机。
    if (((INPUT_DIR 和~ P6IN)&&~(MASTER_TX_BUSY ==(MASTER_TX_BUSY 和 System_Flags))){//查看 INPUT_DIR 是否为低电平以及主 TX 不忙
    if (ATTN_INN &~P2IN){//等待来自上流卡的注意信号。
    //设置上行端口进行接收
    P2DIR = ACK_INN + RDY_IN;//设置输出引脚。
    P2OUT &&~RDY_IN;//将 RDY_IN 置为无效。
    P2OUT &=~ACK_INN;//向上游卡发送确认。

    Upstone_pointer = 0;//初始化数组索引。
    System_Flags |= UPQ_RX_BUSY;//设置 BUSY 标志。
    Upstr_timer = 0;

    Upstr_Pkt_Rd_State = Upstr_Rd_Wait_OE_Low;//转到等待来自上游卡的输出使能。
    }
    }
    中断;

    案例 Upstr_RD_WAIT_OE_Low://等待输出使能变为真。
    如果(ATTN_INN 和~P2IN){//检查以确保传输没有过早终止。
    if (OE_INN &~P2IN){//如果输出使能为低电平,那么...
    Upstr_Pkt_Rd_State = Upstr_Read_Data;//开始从端口收集数据。
    }
    }
    else{UPQ_Pkt_Rd_State = Upstr_Rd_Error;}//传输已终止
    中断;

    案例 Upstr_Read_Data://读取一个字节的数据并存储到 Upqing_Data 中。
    如果(ATTN_INN 和~P2IN){//检查以确保传输没有过早终止。
    if ( OE_INN & P2IN ){//如果 packet 已完成,则退出。
    P2OUT |= ACK_INN;//删除上游卡的确认。
    Upstr_Pkt_Rd_State = Upstr_Rd_Check_OE;//重新布防状态机。
    }
    否则 if ( CLK_IN & P2IN ){
    temp_data= P1IN;//从端口读取数据。
    UPQ_Data[UPQ_POINTER]= Temp_DATAA;//从端口读取数据。
    P2OUT |= RDY_IN;//错误信号正在用作就绪线路。

    // if ( Upstone_pointer < Rx_Packet_Length ){ CmpChecksum += Temp_data;}

    upstone_pointer++;//使字节计数/数组索引递增。

    Upstr_Pkt_Rd_State = Upstr_Rd_wait_CLK_Low;
    }
    }
    else{UPQ_Pkt_Rd_State = Upstr_Rd_Error;}//传输终止
    中断;

    case Upstr_RD_WAIT_CLK_Low://等待 CLK IN 变为低电平、然后清除 READY 行。
    如果(ATTN_INN 和~P2IN){//检查以确保传输没有过早终止。
    if ( CLK_IN &~P2IN ){
    P2OUT &=~RDY_IN;//清除 READY 行。
    Upstr_Pkt_Rd_State = Upstr_Read_Data;
    }
    }
    else{UPQ_Pkt_Rd_State = Upstr_Rd_Error;}//传输终止
    中断;

    Case Upstr_Rd_Check_OE://如果输出使能为 false、则退出、否则获取下一个字节。
    if (ATTN_INN & P2IN){//检查以确保传输没有过早终止。
    System_Flags 并且=~上游_RX_BUSY;//清除 BUSY 标志。
    //待定,使用测试数据和最多 Dnstream 回送进行测试,移除下一行
    System_Flags |= NEW_PKT_RDY;//设置新数据包标志。
    Upstr_Pkt_Rd_State = Upstr_Read_Start;//重新布防状态机。

    //将 UpDtream 端口设置为空闲状态
    P2DIR = 0x00;//所有输入。
    P2REN = 0xFF;//启用上拉。
    P2OUT = ATTN_INN + ACK_INN + OE_INN + SP1_INN + SP2_INN;//信号拉高、未列出拉低。

    }
    中断;

    案例 Upstr_Rd_Error://上游数据包错误、关闭和退出状态机。
    //将 UpDtream 端口设置为空闲状态
    // P2SEL = 0x00;//设置端口所有 GPIO。
    P2DIR = 0x00;//所有输入。
    P2REN = 0xFF;//启用上拉。
    P2OUT = ATTN_INN + ACK_INN + OE_INN + SP1_INN + SP2_INN;//信号拉高、未列出拉低。

    System_Flags 并且=~上游_RX_BUSY;//清除 BUSY 标志。
    Upstr_Pkt_Rd_State = Upstr_Read_Start;//为下一个启动序列初始化状态机。
    中断;
    }//***** 上游数据包读取状态机的末尾*****
    }//字节 Brick_Col >零。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    UCA0BR0 |= 0x05;//波特率预分频的高字节,230,400波特。

    用户指南(SLAU144J)对于230400bps、建议使用 UCBR=4、而不是=5 (UCBRS=5、UCBRF=3、UCOS16=1)、此时 BRCLK=16MHz。 您试过吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    更好、但仅接收1或2个字符。 它正在找到0x5A 数据包标头! 仍在捕获0x5A 后获取 UCOE 和 UCRXERR。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    这似乎极其复杂。 您考虑过中断了吗?

    http://www.simplyembedded.org/tutorials/msp430-uart/

    您还可以查看 Resource Explorer 中的示例。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    UCOE 会有所不同。 这意味着你没有足够快地获取 RXBUF、所以需要(至少)一个完整字节时间(230.4kbps 时为43usec)(字节是否正确)。

    第一个猜测是您在状态机中花费的时间太长。 我没有看到用于检查 OE/RXERR 的代码;您在查看断点处的 UCA0STAT 吗? (调试器交互非常慢。)

    [编辑:修正的措辞——正如 Keith 所指出的那样,没有提到 ISR。]

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    在哪里可以找到有关 MSP430FXXX 微控制器中 ISR 和 UART 数据管理例程的良好 C 代码示例?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    TI 示例如下:

    https://dev.ti.com/tirex/explore/node?node=A__ABSUuF.BG8myJ5a9tne2iA__msp430ware__IOGqZri__LATEST

    它们主要侧重于行使外设(包括中断)、而不是更高级别的功能。

    5分钟后、Google ("MSP430 UART GitHub")提出了一些候选人。 我还没有尝试过它,但从 简短的 skim 说,pepyakin 的"MSP430-UART"示例 有一个环形缓冲器实现,这可能 是有用的 ,并且似乎是(a)相当简单和(b)写的 F2系列。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我同意这种做法过于复杂。 必须是在接收到的字节之间由于~700个 MCLK 而出现溢出错误。

    这是一个不久前为 F249写入的数据包接收例程。 在发生超时的情况下、它使用计时器复位状态机。 专用于9500bps 链路、但足够简单、因此在您的情况下操作应该没问题。 最好用作示例、而不是字面上使用。

     
    __attribute__((interrupt(USCIAB0RX_VECTOR))) void rxISR(void)
    {
      static int i, count;
      int c;
    
      if(IFG2 & UCA0RXIFG)
        {
          if(UCA0STATW & UCRXERR)         // receive error flag set?
            {
              c = UCA0RXBUF;   // drop the received character
              return;
            }
          c = UCA0RXBUF;   // get the received character
          switch(rx_state)
            {
            case 0:     // Drop all received characters in state 0
              break;         
            case 1:     // scanning for SYNC character
              if(c == PSYNC)
                {
                  LED2_ON;
                  TBCCR1 = TBR + CHAR_TIMEOUT;  // reset timeout timer
                  i = 0;
                  rx_state = 2;
                }
              break;
            case 2:
              TBCCR1 = TBR + CHAR_TIMEOUT;  // reset timeout timer
              RPacketBuf[i++] = c;
              if(i == 3)         // this should be the count of bytes in the data packet
                {
                  count = c+5;       // Don't forget the header and CRC
                  rx_state = 3;
                }
              break;
            case 3:
              TBCCR1 = TBR + CHAR_TIMEOUT;  // reset timeout timer
              if(i < BUFSIZE)     // Drop all characters that don't fit buffer
                RPacketBuf[i++] = c;
              if(i >= count)
                {
                  LED2_OFF;
                  P3OUT &= ~TXDEN;          // Disable RS-485 transmitter 
                  rx_state = 0;
                  recv_flag = RECV_OK;
                  TBCCTL1 &= ~CCIE;  // disable compare interrupt
                  add_event(RPACKET);  // add received packet event
                  WAKEUP;
                }
              break;
            default:
              P3OUT &= ~TXDEN;          // Disable RS-485 transmitter
              rx_state = 0;
              recv_flag = RECV_IDLE;
            }
        }
      //  else
      // B0 interrupt
    }
    
    

    更简单的做法是使用 ISR 填充 FIFO 缓冲区、以便允许较慢的前台任务汇编数据包。