void LIN_Slave_init(void)//LINslave初始化
{
UART_ConfigType uartConfig;
uint8_t linCtrl = 0;
memset((void *)&uartConfig, 0, sizeof(UART_ConfigType));
///Init GPIO
GPIO_SetFunc(SWLIN_RX, RXPinFunc);
GPIO_SetFunc(SWLIN_TX, TXPinFunc);
GPIO_SetDir(SWLIN_SLP, GPIO_OUT);
GPIO_SetPinLevel(SWLIN_SLP, GPIO_LEVEL_HIGH);
uartConfig.baudrate = 19200;
uartConfig.dataBits = UART_WORD_LEN_8BIT;
uartConfig.stopBits = UART_STOP_1BIT;
uartConfig.parity = UART_PARI_NO;
uartConfig.dmaEn = UART_DMA_TXRX_NONE;
uartConfig.fifoByteEn = ENABLE;
uartConfig.sampleCnt = UART_SMP_CNT0; ///<must set UART_SMP_CNT0 when use LIN function
uartConfig.callBack = &UartLIN_Handler;
UART_Init(UART_LIN, &uartConfig); ///<Init UART
// Set master or slave mode
//g_mode = mode;
g_state = LIN_STATE_IDLE;
//g_schTblIdx = schTblIdx;
linCtrl = UART_LINCR_LINEN_Msk | UART_LINCR_LBRKIE_Msk | (g_breakThre ? UART_LINCR_LBRKDL_Msk : 0) | (g_autoBaud ? UART_LINCR_LABAUDEN_Msk : 0);
UART_SetLIN(UART_LIN, linCtrl);
// Enable interrupt
UART_SetRXNEInterrupt(UART_LIN, ENABLE);
UART_SetTXEInterrupt(UART_LIN, DISABLE);//不使tx保持空中断
NVIC_ClearPendingIRQ(UART_LIN_IRQn);
NVIC_EnableIRQ(UART_LIN_IRQn);
}
LIN初始化
每收到一个字节数据都产生中断
void UartLIN_Handler(void *device, uint32_t wpara, uint32_t lpara)
{
//printf("UartLIN_Handler\r\n");
// Receive break field
if (0 != (lpara & UART_LSR1_FBRK_Msk))
{
LIN_IfcAux();
UART_LIN->LSR1 |= UART_LSR1_FBRK_Msk; ///<write 1 to clear break status
}
// Receive data
if (0 != (wpara & UART_LSR0_DR_Msk))
{
LIN_IfcRx();
}
// Transmit data done
if (0 != (wpara & UART_LSR0_THRE_Msk))
{
LIN_IfcTx();
}
}
收到break field段后进中断,进入第一个if,在LIN_IfcAux中将标志从初始置为LIN_STATE_RECEIVE_SYNC,那么下一次收到中断将进入LIN_IfcRx()
void LIN_IfcAux(void)
{
printf("LIN_Handler1\r\n");
if (g_state == LIN_STATE_IDLE)
{
g_state = g_autoBaud ? LIN_STATE_RECEIVE_IDENTIFIER : LIN_STATE_RECEIVE_SYNC;
//g_direction = DIR_RX;
//g_txCount = 0;
g_rxCount = 0;
}
else
{
printf("Frame err\r\n");
g_state = g_autoBaud ? LIN_STATE_RECEIVE_IDENTIFIER : LIN_STATE_RECEIVE_SYNC;
//g_direction = DIR_RX;
//g_txCount = 0;
g_rxCount = 0;
}
if (g_state == LIN_STATE_SEND_BREAK)
{
g_state = LIN_STATE_SEND_SYNC;
UART_SetTXEInterrupt(UART_LIN, ENABLE);//使tx保持空中断
}
}
void LIN_IfcRx(void)
{
uint8_t data = 0, id = 0, index = 0, checksum = 0, frameNum = 0;
data = UART_ReceiveData(UART_LIN);
//printf("LIN_Handler2 data=0x%02x\r\n", data);
if (g_state == LIN_STATE_RECEIVE_SYNC)
{
// Check sync field
if (data == 0x55)
{
g_state = LIN_STATE_RECEIVE_IDENTIFIER;
//printf("LIN_Handler2 0x55\r\n");
}
else
{
g_state = LIN_STATE_IDLE;
//printf("Sync err\r\n");
}
}
else if (g_state == LIN_STATE_RECEIVE_IDENTIFIER)
{
// Check protect id
id = data & 0x3F;
uint8_t check_pid = LIN_MakeProtId(id);
//printf("LIN_Handler2 id=0x%02x, check_pid=0x%02x\r\n", id, check_pid);
if(data == check_pid && id == 0x05)
{
g_state = LIN_STATE_RECEIVE_DATA;
}
else if (data == check_pid && id == 0x10)
{
g_state = LIN_STATE_SEND_DATA;
}
else
{
g_state = LIN_STATE_IDLE;
//printf("Pid err\r\n");
}
}
else if (g_state == LIN_STATE_RECEIVE_DATA)
{
//printf("LIN_Handler2 g_rxCount=0x%02x\r\n", g_rxCount);
if (g_rxCount < 8)
{
g_buffer[g_rxCount] = data;
g_rxCount++;
}
// Receive frame done
if (g_rxCount >= 8)
{
printf("Receive frame done\r\n");
for(int k = 0; k < 8;k++ )
{
printf(" %02x ", g_buffer[k]);
}
printf("\r\n");
g_state = LIN_STATE_IDLE;
}
}
if(g_state == LIN_STATE_SEND_DATA)
{
//UART_SendData(UART_LIN, 0x55);
//UART_SendData(UART_LIN, LIN_MakeProtId(0x10));
checksum = LIN_MakeChecksum( LIN_MakeProtId(0x10), 8, g_buffer);
for(int k = 0; k<8; k++)
{
UART_SendData(UART_LIN, g_buffer[k]);
}
UART_SendData(UART_LIN, checksum);
printf("checksum = %x\r\n",checksum);
printf("Send frame done\r\n");
g_state = LIN_STATE_IDLE;
}
}
通过data = UART_ReceiveData(UART_LIN);获得收到的一字节数据
接收到同步段0x55后,在LIN_IfcRx中,状态为LIN_STATE_RECEIVE_SYNC时检测同步段,即0x55,此后标志置为LIN_STATE_RECEIVE_IDENTIFIER
收到PID,在LIN_IfcRx中,状态置为LIN_STATE_RECEIVE_IDENTIFIER,并校验收到的PID,如果收到的id为0x05(此处ID自己定的),说明master发的是写指令,对于从节点需要读取master写的数据,状态置为LIN_STATE_RECEIVE_IDENTIFIER继续接收数据段;如果收到的id为0x10,说明master发的是读指令,对于从节点需要发出需要发送的数据,状态置为LIN_STATE_SEND_DATALIN_STATE_SEND_DATA
如果收到的id为0x05,下一字节开始收到数据段,每收到一字节数据都放入g_buffer中
如果收到的id为0x10,开始发数据
checksum = LIN_MakeChecksum( LIN_MakeProtId(0x10), 8, g_buffer) 为计算校验和,函数如下代码所示。校验和有经典型和增强型两种,区别仅在于增强型校验需要计算的范围是除了数据段还要加上ID的数值,此处用的增强型。
从节点仅发送数据段与校验,通过UART_SendData(UART_LIN, g_buffer[k])发送数据段,UART_SendData(UART_LIN, checksum);发送了校验。
从节点发完数据将标志置为LIN_STATE_IDLE(初始状态)
g_state = LIN_STATE_IDLE;
其他注意:不要在接收与发送数据过程中放printf
使用队列