236 lines
5.8 KiB
C
236 lines
5.8 KiB
C
#include "bsp_lin.h"
|
||
#include "circular_buffer.h"
|
||
|
||
|
||
static lin_error_enum lin_error = FIFO_VOID;
|
||
static lin_rxstate_enum lin_rxstateget = BREAK_GET;
|
||
static lin_msg_struct lin_msg = {0};
|
||
static CircBuf_t lin_rx_circbuf = {0};//接收环形队列索引
|
||
|
||
|
||
void lin_init(void)
|
||
{
|
||
gpio_init_type gpio_init_struct;
|
||
|
||
crm_periph_clock_enable(CRM_USART5_PERIPH_CLOCK, TRUE);
|
||
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
|
||
|
||
// TX引脚配置
|
||
gpio_default_para_init(&gpio_init_struct); // 清空结构体
|
||
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE; // 中等驱动强度
|
||
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN; // 推挽输出
|
||
gpio_init_struct.gpio_mode = GPIO_MODE_MUX; // 引脚复用模式
|
||
gpio_init_struct.gpio_pins = GPIO_PINS_3; // TX引脚
|
||
gpio_init_struct.gpio_pull = GPIO_PULL_NONE; // 无上下拉
|
||
gpio_init(GPIOB, &gpio_init_struct); // 初始化TX引脚
|
||
|
||
gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE3, GPIO_MUX_10);
|
||
|
||
// RX引脚配置
|
||
gpio_init_struct.gpio_mode = GPIO_MODE_MUX; // 输入模式
|
||
gpio_init_struct.gpio_pins = GPIO_PINS_4; // RX引脚
|
||
gpio_init(GPIOB, &gpio_init_struct); // 初始化RX引脚
|
||
|
||
gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE4, GPIO_MUX_10);
|
||
|
||
// USART配置
|
||
usart_init(USART5, Lin_Speed, USART_DATA_8BITS, USART_STOP_1_BIT);
|
||
usart_transmitter_enable(USART5, TRUE); // 使能发送器
|
||
usart_receiver_enable(USART5, TRUE); // 使能接收器
|
||
usart_parity_selection_config(USART5, USART_PARITY_NONE); // 无奇偶校验
|
||
usart_break_bit_num_set(USART5, USART_BREAK_11BITS); // 断帧检测
|
||
usart_lin_mode_enable(USART5, TRUE); // 启用LIN模式
|
||
|
||
// 中断配置
|
||
nvic_irq_enable(USART5_IRQn, 0, 0); // 配置串口优先级
|
||
usart_enable(USART5, TRUE); // 使能USART1
|
||
usart_interrupt_enable(USART5, USART_BF_INT, TRUE); // 使能帧中断
|
||
usart_interrupt_enable(USART5, USART_RDBF_INT,TRUE);// 使能串口接收中断
|
||
|
||
CircBuf_Alloc(&lin_rx_circbuf, sizeof(lin_msg_struct)*2);
|
||
}
|
||
|
||
uint8_t lin_getpid(uint8_t id)
|
||
{
|
||
uint8_t pid = 0, p0 = 0, p1 = 0;
|
||
|
||
p0 = (((id>>0)^(id>>1)^(id>>2)^(id>>4))&0x01)<<6;//偶校验位
|
||
p1 = ((~((id>>1)^(id>>3)^(id>>4)^(id>>5)))&0x01)<<7;//奇校验位
|
||
pid = (id|p0|p1);
|
||
return pid;
|
||
}
|
||
|
||
uint8_t lin_getchecksum(uint8_t pid, uint8_t* p_data, uint8_t data_len, uint8_t flag)
|
||
{
|
||
uint16_t checksum = 0;
|
||
if((pid != 0x3c)&&(pid != 0x7d))
|
||
{
|
||
checksum = pid;
|
||
}
|
||
for(uint8_t i = 0; i < data_len; i++)
|
||
{
|
||
checksum += p_data[i];
|
||
if(checksum > 0xff)
|
||
{
|
||
checksum -=0xff;
|
||
}
|
||
}
|
||
|
||
if(flag == 0)
|
||
{
|
||
return (~checksum) & 0xff; //发送方需要取反
|
||
}
|
||
else
|
||
{
|
||
return checksum & 0xff; //接收方不需要
|
||
}
|
||
}
|
||
|
||
void lin_send_bytes(usart_type * usart_x, uint8_t* p_data, uint8_t data_len)
|
||
{
|
||
for(uint8_t i = 0; i < data_len; i++)
|
||
{
|
||
usart_data_transmit(usart_x, *p_data++);
|
||
while(usart_flag_get(USART3, USART_TDBE_FLAG) == RESET);
|
||
}
|
||
}
|
||
|
||
void lin_rx_data(uint8_t pid, uint8_t* p_data, uint8_t data_len)
|
||
{
|
||
uint8_t lin_buffer[data_len + 1];
|
||
uint8_t checksum = lin_getchecksum(pid, p_data, data_len, 0);
|
||
|
||
for(uint8_t i = 0; i < data_len; i++)
|
||
{
|
||
lin_buffer[i] = *(p_data + i);
|
||
}
|
||
|
||
lin_buffer[data_len] = checksum;
|
||
lin_send_bytes(USART3,lin_buffer, data_len + 1);
|
||
}
|
||
|
||
|
||
void lin_master_rxmsg(uint8_t data)
|
||
{
|
||
lin_msg_struct* p_lin_msg = &lin_msg;
|
||
|
||
switch((uint8_t)lin_rxstateget)
|
||
{
|
||
case BREAK_GET:
|
||
break;
|
||
case SYNCH_GET:
|
||
{
|
||
if(data != 0x55)
|
||
{
|
||
lin_error = SYNC_ERR;
|
||
lin_rxstateget = BREAK_GET;
|
||
}
|
||
else
|
||
{
|
||
p_lin_msg->sync = data;
|
||
lin_rxstateget = PID_GET;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case PID_GET:
|
||
{
|
||
p_lin_msg->frameid = data&0x3f;
|
||
p_lin_msg->pid = data;
|
||
uint8_t pid = lin_getpid(p_lin_msg->frameid);
|
||
|
||
if(pid == p_lin_msg->pid)
|
||
{
|
||
if(p_lin_msg->frameid == 0x03) //执行 即继续接收数据
|
||
{
|
||
lin_rxstateget = MSG_GET;
|
||
p_lin_msg->datalen = 0;
|
||
}
|
||
else if(p_lin_msg->frameid == 0x32) //反馈 即向lin总线发送消息
|
||
{
|
||
lin_rx_data(p_lin_msg->pid, &data, 1);
|
||
lin_rxstateget = BREAK_GET;
|
||
}
|
||
else
|
||
{
|
||
lin_rxstateget = BREAK_GET;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
lin_error = PID_ERR;
|
||
lin_rxstateget = BREAK_GET;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case MSG_GET:
|
||
{
|
||
p_lin_msg->data[p_lin_msg->datalen++] = data;
|
||
lin_rxstateget = (p_lin_msg->datalen >= 8) ? CHECKSUM_GET:MSG_GET;
|
||
}
|
||
break;
|
||
|
||
case CHECKSUM_GET:
|
||
{
|
||
p_lin_msg->checksum = data;
|
||
uint8_t checksum = lin_getchecksum(p_lin_msg->pid, p_lin_msg->data, p_lin_msg->datalen, 1);
|
||
if((checksum + p_lin_msg->checksum) == 0xff)
|
||
{
|
||
CircBuf_Push(&lin_rx_circbuf, (uint8_t *)p_lin_msg, sizeof(lin_msg_struct));
|
||
}
|
||
else
|
||
{
|
||
lin_error = FORMAT_ERR;
|
||
}
|
||
lin_rxstateget = BREAK_GET;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
lin_rxstateget = BREAK_GET;
|
||
break;
|
||
}
|
||
}
|
||
|
||
uint8_t rx_ring_buffer_get_lin_msg(lin_msg_struct * p_lin_msg)
|
||
{
|
||
return CircBuf_Pop(&lin_rx_circbuf,(uint8_t*)p_lin_msg, sizeof(lin_msg_struct));
|
||
}
|
||
|
||
void USART5_IRQHandler(void)
|
||
{
|
||
uint8_t receive_data = 0;
|
||
|
||
|
||
if(RESET != usart_interrupt_flag_get(USART5,USART_BFF_FLAG))
|
||
{
|
||
usart_data_receive(USART5);
|
||
|
||
lin_rxstateget = SYNCH_GET;
|
||
|
||
usart_flag_clear(USART5,USART_FERR_FLAG);//清除帧错误标志,lin断开段也是数据,只不过断开段是超过10位的0,不符合串口的帧标准,所以出现了帧错误
|
||
usart_flag_clear(USART5,USART_BFF_FLAG);
|
||
usart_flag_clear(USART5,USART_RDBF_FLAG);
|
||
return ;
|
||
}
|
||
|
||
if(RESET != usart_interrupt_flag_get(USART5,USART_RDBF_FLAG))
|
||
{
|
||
receive_data = usart_data_receive(USART5);
|
||
if(RESET == usart_interrupt_flag_get(USART5,USART_FERR_FLAG))
|
||
{
|
||
if((receive_data == 0x55)&&(lin_rxstateget == BREAK_GET))
|
||
{
|
||
lin_rxstateget = SYNCH_GET;
|
||
return ;
|
||
}
|
||
|
||
lin_master_rxmsg(receive_data);
|
||
}
|
||
|
||
usart_flag_clear(USART5,USART_RDBF_FLAG);
|
||
}
|
||
}
|
||
|