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.

[参考译文] MSP430FR2633:MSP430 UART 在中断时发送

Guru**** 2587365 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/940118/msp430fr2633-msp430-uart-transmit-on-interrupt

器件型号:MSP430FR2633

您好!  

我将移植 freemodbus 库以与 MSP430FR26xx 配合使用(https://github.com/cwalter-at/freemodbus)

该库在中断时进行 UART 发送。 我认为我的传输代码流有问题:

/* UART_init */

bool
xMBPortSerialInit( UCHAR ucPort、Ulong ulBaudRate、UCHAR ucDataBits、eMBParity eParity )
{
布尔 b 初始化= true;

//配置 UART 引脚
GPIO_setPeripheralModuleFunctionOutputPin (GPIO_PORT_P1、GPIO_PIN4、GPIO_PRIMARY_MODULE_Function);
GPIO_setPeripheralModuleFunctionInputPin (GPIO_PORT_P1、GPIO_PIN5、GPIO_PRIMARY_MODULE_Function);

//配置 UART
//SMCLK = 1MHz、波特率= 115200
//UCBRx = 8、UCBRFx = 0、UCBRSx = 0xD6、UCOS16 = 0
EUSCI_A_UART_initParam param ={0};
//选择时钟源
param.selectClockSource = EUSCI_A_UART_CLOCKSOURCE_SMCLK;
//时钟预分频器为 UCBRx = int (N / 16)、其中 N = clock_frequency / baud _rate
//int (N / 16)= int (2000000 / ulBaudRate / 16)
param.clockPrescalar = SMCLK_FREQ_MHz * 1000000/ ulBaudRate / 16;
//控制过采样模式的 UCBRF 位
开关(ulBaudRate)
{
情况9600:
//选择过采样波特率模式
param.oversaming= eUSCI_A_UART_oversaming_BAUDRATE_generation;//最大 eUSCI_A 波特率为 UART 源时钟频率 BRCLK 的1/16
//UCBRF = int ((((N/16)- int (N/16)))* 16)= int ((((208.3333333/16)- int (208.33333316/16))* 16)= int (0.3333)= 0
param.firstModReg = 0;
//请参阅用户指南中的表22-4以查找与 UCBRF 编号对应的寄存器值
// N 的小数部分= 0.3333
//在表中,0.3333 <--> 0x49
param.secondModReg = 0x49;
中断;
案例115200://不起作用-波特率错误
//选择低频率波特率模式
param.oversaming= EUSCI_A_UART_LOW_FREQUENCY BAUDRATE_generation;
//UCBRF = int ((((N/16)- int (N/16)))* 16)= int ((((17.3611/16)- int (17.3611/16))* 16)= int (0.3611)= 0
param.firstModReg = 0;
//请参阅用户指南中的表22-4以查找与 UCBRF 编号对应的寄存器值
// N 的小数部分= 0.3611
//在表中,0.3611 <--> 0x52
param.secondModReg = 0xD6;
中断;
}
//最低或最高有效位优先
param.msborLsbFirst = EUSCI_A_UART_LSB_FIRST;
//选择一个或两个停止位
param.numerofStopBits = EUSCI_A_UART_Oe_STOP_BIT;
//选择是否使用多处理器/自动波特模式
param.uartMode = EUSCI_A_UART_MODE;

//控制奇偶校验位-请注意 eZ-FET 不支持奇偶校验位
开关(eParity)
{
//控制奇偶校验位-请注意 eZ-FET 不支持奇偶校验位
案例 MB_PAR_NONE:
param.parity = EUSCI_A_UART_NO_parity;
中断;
案例 MB_PAR_ODD:
param.parity = EUSCI_A_UART_ODD 奇偶校验;
中断;
案例 MB_PAR_LEVen:
param.parity = EUSCI_A_uart_evo_parity;
中断;
}

if (bInitialized)
{
/*启用 UART */
b 初始化= EUSCI_A_UART_INIT (EUSCI_A0_BASE、&param);
EUSCI_A_UART_ENABLE (EUSCI_A0_BASE);
}
返回 bInitialized;
} 

/*然后是 UART 使能(TX 或 RX)*(也应该使能中断)/  

void
vMBPortSerialEnable( BOOL xRxEnable,BOOL xTxEnable )
{
if (xRxEnable)
{
EUSCI_A_UART_clearInterrupt (EUSCI_A0_BASE、EUSCI_A_UART_receive_interrupt);
EUSCI_A_UART_enableInterrupt (EUSCI_A0_BASE、EUSCI_A_UART_receive_interrupt);
}
其他
{
EUSCI_A_UART_clearInterrupt (EUSCI_A0_BASE、EUSCI_A_UART_receive_interrupt);
}
if (xTxEnable)
{
EUSCI_A_UART_enableInterrupt (EUSCI_A0_BASE、EUSCI_A_UART_Transmit _INTERRUPT);
}
其他
{
EUSCI_A_UART_DisableInterrupt (EUSCI_A0_BASE、EUSCI_A_UART_Transmit 中断);
}
} 

/*然后是 SEND_BYTE 或 Receive_byte

bool
xMBPortSerialPutByt( char ucByte )
{
EUSCI_A_UART_transmitData (EUSCI_A0_BASE、ucByte);
返回 true;
}

BOOL
xMBPortSerialGetByte (char * pucByte)
{
* pucByte = EUSCI_A_UART_receiveData (EUSCI_A0_BASE);
返回 true;
}

/* ISR */

void USCI_A0_ISR (void)
{
switch (__evo_in_range (UCA0IV、USCI_UART_UCTXCPTIFG))
{
USCI_NONE 案例:中断;
USCI_UART_UCRXIFG 案例:
debug_toggle_RX();
pxMBFrameCBByteRecept接收 器(); //调用 xMBASCIIReceiveFSM()
中断;
USCI_UART_UCTXIFG 案例:
debug_toggle_tx();
pxMBFrameCBTransmitterEmpty(); //调用 xMBASCIITransmitFSM()
中断;
案例 USCI_UART_UCSTTIFG:中断;
案例 USCI_UART_UCTXCPTIFG:break;
}
} 

说明

  • 库中的上层应在开始时初始化 UART (xMBPortSerialInit),然后调用 vMBPortSerialEnable 以启用仅 RX,
  • 当一个帧被接收(成功执行)时、它通过发送一个帧进行响应、所以 它 vMBPortSerialEnable 启用 TX、然后发送一个帧(多个字节)
  • 然后、它应该返回到初始状态(问题所在)...

尽管代码调试器显示函数 EUSCI_A_UART_enableInterrupt (EUSCI_A0_BASE、EUSCI_A_UART_SEND_INTERRUPT)、但此后从未触发 TX 中断、我只能发送1帧;为什么调用?

 


以下是初始(工作状态之前)的寄存器值屏幕截图:

下面是非工作状态之前的屏幕截图:

e2e.ti.com/.../portserial.c

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

    读取 UCA0IV 会清除相关中断(在本例中为 UCTXIFG)、因此您的软件必须跟踪发生中断的事实。  

    重新启用时、原始代码看起来像是显式设置 UTXIFG0、这通常很危险、但我认为这里是可以的、因为协议是完全半双工的。

    我这样做的方法是用对 UCTXIFG/UCRXIFG 的显式检查替换开关(UCA0IV)、这不会清除它们。 因此 、当 xMBASCIITransmitFSM (最终)在 数据包末尾调用 vMBPortSerialEnable( true、false )时、UCTXIFG 仍将被置位;这将用作"助记符设备"。

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

    感谢 Bruce 的回答。

    我只是把它作为原始代码执行、它起作用了。  

    void
    vMBPortSerialEnable( BOOL xRxEnable,BOOL xTxEnable )
    {
    enter_critical section();
    
    if (xRxEnable)
    {
    EUSCI_A_UART_enableInterrupt (EUSCI_A0_BASE、EUSCI_A_UART_receive_interrupt);
    }
    其他
    {
    EUSCI_A_UART_DisableInterrupt (EUSCI_A0_BASE、EUSCI_A_UART_receive_interrupt);
    }
    if (xTxEnable)
    {
    EUSCI_A_UART_enableInterrupt (EUSCI_A0_BASE、EUSCI_A_UART_Transmit 中断);
    UCA0IFG |= UCTXIFG;
    }
    其他
    {
    EUSCI_A_UART_DisableInterrupt (EUSCI_A0_BASE、EUSCI_A_UART_Transmit 中断);
    }
    exit_critical section();
    }