📄 lin_low_level.c
字号:
LIN_CONTROL_REG = 0x80;
#endif
#endif
return;
}
/**********************************************************************
* Function Name: lin_set_ifc_status()
* Description: Updates the LIN interface status word.
* Parameters: ident - LIN message ID
* status - new status value
* Returns: Nothing.
* Ext. References: LIN_ifc_status
* Preemptible: Yes.
* Reentrant: Yes.
*********************************************************************/
void lin_set_ifc_status(unsigned char ident, unsigned char status)
{
/* If "ident" is not 0xFF and the existing ident byte of the status
* word has already been set, set the overrun status bit. */
if ((ident != LIN_ID_NOTSET) && (LIN_ifc_status[1] != 0))
{
LIN_ifc_status[0] |= LIN_IFC_OVERRUN;
}
/* If "ident" is not 0xFF, set the ident byte of the status word
* to "ident". */
if (ident != LIN_ID_NOTSET)
{
LIN_ifc_status[1] = ident;
}
/* OR the new status with the existing status. */
LIN_ifc_status[0] |= status;
return;
}
#if (LIN_MASTER_NODE == LIN_MY_NODE_NAME)
#ifdef USE_POWER_CONTROL /* Implemented only if power control is used. */
/**********************************************************************
* Function Name: lin_goto_sleep()
* Description: Send the LIN sleep command from a LIN Master node.
* Parameters: None.
* Returns: Nothing.
* Ext. References: LIN_ident_PB, LIN_data[], LIN_DIAG_mode.
* Preemptible: Yes.
* Reentrant: No.
*********************************************************************/
void lin_goto_sleep(void)
{
unsigned char i;
/* Generate a LIN message header byte using ID 0x60 (Master Diagnostic Request
* Frame). The ID byte is written into the global variable "LIN_ident_PB". */
LIN_ident = 0x3C;
LIN_ident_PB = lin_make_protected_identifier(0x3C);
/* Load the sync byte into LIN message byte 0. */
LIN_data[0] = 0x55;
/* Load the header byte into LIN message byte 1. */
LIN_data[1] = LIN_ident_PB;
/* Copy the LIN "go_to_sleep" data (including checksum) into the LIN message
* bytes 2 through 10. */
for (i = 0; i < 9; i++)
{
LIN_data[(i + 2)] = LIN_sleep_cmd[i];
}
LIN_DIAG_mode = 1;
/* Send the LIN break to start the message frame. */
lin_send_break();
}
#endif /* USE_POWER_CONTROL. */
#endif /* Master node. */
/**********************************************************************
* Function Name: lin_change_node_status()
* Description: Configures the LIN node to operate in the requested
* state.
* Parameters: status - the desired node state.
* Returns: Nothing.
* Ext. References: LIN_node_status
* Preemptible: Yes.
* Reentrant: Yes.
*********************************************************************/
void lin_change_node_status(unsigned char status)
{
LIN_node_status = status;
BRK_TMR_RUN = 0; /* Stop the break timer. */
BRK_TMR_INT_CTL = 0x00; /* Disable the break timer interrupt. */
BRK_TMR_INT_CFG &= BRK_INT_NONE; /* Clear all break timer interrupt source enables. */
BRK_TMR_FLAGS |= BRK_CLR_ALL_FLGS; /* Clear all break timer interrupt flags. */
switch (status)
{
case DISCONNECT:
LIN_FUNCTION_ENABLE = 0; /* Disable the LIN function block. */
#if (LIN_MASTER_NODE == LIN_MY_NODE_NAME)
#ifdef DEDICATED_SCHEDULE_TIMER
SCH_TMR_RUN = 0; /* Stop the LIN schedule timer. */
SCH_TMR_INT_CFG = SCH_INT_DIS; /* Disable the schedule timer interrupt. */
#endif
LIN_schedule_stop_flag = 1; /* Halt Master schedule action. */
#endif
LIN_UART_OP_MODE = LIN_UART_OP_OFF; /* Disable the serial port. */
LIN_UART_RX_INT_CTL = 0x00; /* Disable the UART interrupts. */
LIN_UART_TX_INT_CTL = 0x00;
API_AWAKE_FLG = 0; /* Clear LIN_AWAKE_FLG. */
break;
case CONNECT:
#if (LIN_MASTER_NODE == LIN_MY_NODE_NAME)
/* This is a LIN Master node. */
#ifdef DEDICATED_SCHEDULE_TIMER
SCH_TMR_RUN = 1; /* Start the LIN schedule timer. */
SCH_TMR_INT_CFG = SCH_INT_EN; /* Enable the schedule timer interrupt. */
#endif
LIN_schedule_stop_flag = 0; /* Start Master schedule action. */
#else
/* This is a LIN Slave node. */
/* Reload the break timer count. */
BRK_TMR_PRECNT_REG = LIN_break_prescale;
BRK_TMR_CNT_REG = LIN_break_count;
/* Configure the LIN function mode and interrupt sources. The Break interrupt
* is always enabled and the Sync interrupt is enabled in the SYNC_AUTO_MODE. */
#ifdef SYNC_AUTO_MODE
BRK_TMR_INT_CFG = 0xA3;
#else
BRK_TMR_INT_CFG = 0x82;
#endif
BRK_TMR_INT_CTL = BRK_TMR_INT_PRIO; /* Enable the break timer interrupt. */
BRK_TMR_RUN = 1; /* Start the break timer. */
BRK_TMR_ARMED = 1; /* Enable break pulse detection mode. */
#endif
LIN_UART_OP_MODE = LIN_UART_OP_OFF; /* Disable the serial port. */
LIN_UART_RX_INT_CTL = 0x00;
LIN_UART_TX_INT_CTL = 0x00;
API_AWAKE_FLG = 1; /* Set LIN_AWAKE_FLG. */
break;
#ifdef USE_POWER_CONTROL
case SLEEP_STATE:
#if (LIN_MASTER_NODE == LIN_MY_NODE_NAME)
/* Reconfigure the break timer mode control bits to detect a wake-up pulse
* according to the hardware being used. */
BRK_TMR_MODE_REG = BRK_TMR_SLV_MODE;
BRK_TMR_IO_REG = BRK_TMR_SLV_IO;
#endif
/* Reload the break timer count to detect a wake-up pulse. */
BRK_TMR_PRECNT_REG = LIN_wake_up_period;
BRK_TMR_CNT_REG = 14;
lin_change_bus_status(QUIET_STATE); /* Place the bus in the QUIET state. */
/* Configure the LIN function mode and interrupt sources. Only the Break
* interrupt is enabled. */
BRK_TMR_INT_CFG = 0xA2;
BRK_TMR_INT_CTL = BRK_TMR_INT_PRIO; /* Enable the break timer interrupt. */
BRK_TMR_RUN = 1; /* Start the break timer. */
BRK_TMR_ARMED = 1; /* Enable break pulse detection mode. */
LIN_UART_OP_MODE = LIN_UART_OP_OFF; /* Disable the serial port. */
LIN_UART_RX_INT_CTL = 0x00;
LIN_UART_TX_INT_CTL = 0x00;
API_AWAKE_FLG = 0; /* Clear LIN_AWAKE_FLG. */
/* Set the interface status to sleep mode. */
lin_set_ifc_status(LIN_ID_NOTSET, LIN_IFC_GOTOSLEEP) ;
break;
case WAKE_UP_STATE:
#if (LIN_MASTER_NODE == LIN_MY_NODE_NAME)
/* This is a Master node. Disable the Break timer. */
/* Reconfigure the break timer mode control bits to Master mode. */
BRK_TMR_MODE_REG = BRK_TMR_MST_MODE;
BRK_TMR_IO_REG = BRK_TMR_MST_IO;
/* Reload the break timer count. */
BRK_TMR_PRECNT_REG = LIN_break_prescale;
BRK_TMR_CNT_REG = LIN_break_count;
#ifdef DEDICATED_SCHEDULE_TIMER
SCH_TMR_RUN = 1; /* Restart the LIN schedule timer. */
#endif
LIN_schedule_stop_flag = 0; /* Start Master schedule action. */
#else
/* This is a Slave node. */
/* Clear "LIN_sleep_timer" to keep the node from going right back to sleep. */
LIN_sleep_timer = 0;
/* Reload the break timer count. */
BRK_TMR_PRECNT_REG = LIN_break_prescale;
BRK_TMR_CNT_REG = LIN_break_count;
/* Configure the LIN function mode and interrupt sources. The Break interrupt
* is always enabled and the Sync interrupt is enabled in the SYNC_AUTO_MODE. */
#ifdef SYNC_AUTO_MODE
BRK_TMR_INT_CFG = 0xA3;
#else
BRK_TMR_INT_CFG = 0x82;
#endif
BRK_TMR_INT_CTL = BRK_TMR_INT_PRIO; /* Enable the break timer interrupt. */
BRK_TMR_RUN = 1; /* Start the break timer. */
BRK_TMR_ARMED = 1; /* Enable break pulse detection mode. */
#endif
lin_change_bus_status(QUIET_STATE); /* Place the bus in the QUIET state. */
API_AWAKE_FLG = 1; /* Set LIN_AWAKE_FLG. */
break ;
#endif /* USE_POWER_CONTROL. */
}
return;
}
/**********************************************************************
* Function Name: lin_change_bus_status()
* Description: Set the LIN bus status to the desired state and
* configure the serial port accordingly.
* Parameters: status - desired bus state.
* Returns: Nothing.
* Ext. References: LIN_bus_state
* Preemptible: Yes.
* Reentrant: No.
*********************************************************************/
void lin_change_bus_status(unsigned char status)
{
/* Set "LIN_bus_status" to the new bus state. */
LIN_bus_status = status;
#if ((LIN_MASTER_NODE != LIN_MY_NODE_NAME) && (defined USE_POWER_CONTROL))
/* Clear "LIN_sleep_timer" on every bus state change, but do it here
* most specifically so the timer is cleared even before the Break
* timer ISR exits. */
LIN_sleep_timer = 0;
#endif /* Slave node and USE_POWER_CONTROL is defined. */
/* The original API code (written for the H8/Tiny family) cleared the serial
* port flags here, which was possible to do since the serial port flags can
* be cleared on the H8/Tiny without affecting UART operation. For the M16C
* and R8C families, two of the serial port flags used (receive complete and
* framing error) are cleared by reading the receive data register. The
* overrun error flag is cleared only by clearing the receive enable bit
* (clears framing error as well) or by de-allocating the UART (which clears
* all three). Any of these actions could potentially cause problems if
* performed here unnecessarily. Since the receive enable bit is cleared in
* several of the bus states, the error flags will be forcefully cleared
* when entering these states. It has been decided not to perform any
* other "special" operations at this point to clear serial port flags. */
/* The UART transmit function remains enabled literally continuously
* to insure that the UART will begin transmitting immediately after
* a byte is written to the UART transmit buffer. Turning on the 'TE'
* bit in the UART mode register only when needed was causing a 500us
* to 700us "pause" between the end of the break period and the sync
* byte (Master) and a similar "pause" between the ID byte and the first
* data byte (Slave) on the H8/Tiny family of processors. Leaving the
* 'TE' bit always enabled eliminated these "pauses" and allowed the LIN
* signal to be generated as specified. This same practice (leaving the
* 'TE' bit set under most circumstances) was followed for the M16C and
* R8C families of processors, without really knowing if it is needed. */
switch (status) {
case QUIET_STATE:
LIN_TX_count = 0;
LIN_RX_count = 0;
/* Disable the bus collision interrupt and clear all flags. */
BRK_TMR_FLAGS |= BRK_CLR_ALL_FLGS;
#if (LIN_MASTER_NODE == LIN_MY_NODE_NAME)
BRK_TMR_INT_CFG = 0xC0; /* Break detect not enabled for Master node. */
#else
/* Configure the LIN function mode and interrupt sources. The Break interrupt
* is always enabled and the Sync interrupt is enabled in the SYNC_AUTO_MODE. */
#ifdef SYNC_AUTO_MODE
BRK_TMR_INT_CFG = 0xB3;
#else
BRK_TMR_INT_CFG = 0x92;
#endif
#endif
LIN_UART_OP_MODE = LIN_UART_OP_IDLE; /* Configure the serial port. */
LIN_UART_RX_INT_CTL = 0x00;
LIN_UART_TX_INT_CTL = 0x00;
/* Receive interrupt disabled
* Receive disabled
* Transmit end interrupt disabled
* Transmit enabled. */
break ;
case SYNC_RECEIVE_STATE:
#ifdef SYNC_AUTO_MODE
/* Turn off the serial port while the sync byte width measurement is
* being made. */
LIN_UART_OP_MODE = LIN_UART_OP_IDLE; /* Configure the serial port. */
LIN_UART_RX_INT_CTL = 0x00;
LIN_UART_TX_INT_CTL = 0x00;
/* Receive interrupt disabled
* Receive disabled
* Transmit end interrupt disabled
* Transmit enabled. */
#else
/* Enable the serial port to "read" the sync byte. */
LIN_UART_OP_MODE = LIN_UART_OP_RCV; /* Configure the serial port. */
LIN_UART_RX_INT_CTL = LIN_UART_RX_INT_PRIO;
LIN_UART_TX_INT_CTL = 0x00;
/* Receive interrupt enabled
* Receive enabled
* Transmit end interrupt disabled
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -