📄 lin_slave.c
字号:
}
}
else
{
}
break;
case RUN_TX_DATA: // 进入接收数据子状态
if(ir_s0tic == YES) // 是否有数据进来
{
ir_s0tic = NO; // 清除uart接收中断查询标志
// 将数据一一发送出去
if(cur_processing_data < dlc_convert[rec_pidl.pid_str.dlc])
{
u0tbl = lin_slave_buffer.data[cur_processing_data];
cur_processing_data ++;
}
else
{
// 发送校验和
cur_processing_data = 0;
u0tbl = lin_slave_buffer.checksum;
run_status = RUN_TX_CHECKSUM; // 进入发送校验和子状态
}
}
else
{
}
break;
case RUN_RX_DATA: // 进入数据接收子状态
if(ir_s0ric == YES) // 接收完成
{
ir_s0ric = NO; // 清除接收中断查询标志
// 将数据一一接收
if(cur_processing_data < dlc_convert[rec_pidl.pid_str.dlc])
{
lin_slave_buffer.data[cur_processing_data] = u0rbl;
uarth_error_buf = u0rbh;
uart_error_test(uarth_error_buf);
cur_processing_data ++;
}
else
{
// 接收校验和
lin_slave_buffer.checksum = u0rbl;
uarth_error_buf = u0rbh;
uart_error_test(uarth_error_buf);
//禁止uart接收,必须
re_u0c1 = LDIS;
/*--------------本地计算校验和----------------*/
// 将数据字节逐加,一旦大于或等于256时就减去255,结果不用取反
lp_data_comm = 0;
local_checksum = 0;
lp_dlc_comm = dlc_convert[rec_pidl.pid_str.dlc];
while(lp_dlc_comm > 0)
{
if ((uint16)local_checksum + lin_slave_buffer.data[lp_data_comm] >= 256U)
{
local_checksum += lin_slave_buffer.data[lp_data_comm];
local_checksum ++;
}
else
{
local_checksum += lin_slave_buffer.data[lp_data_comm];
}
lp_data_comm ++;
lp_dlc_comm --;
}
/*--------------本地计算校验和结束----------------*/
// 检测校验和是否正确
if(local_checksum + lin_slave_buffer.checksum != (uchar8)0xff)
{
lin_cmd = CMD_ERROR;
error_code = LINRX_CHECKSUM_ERROR;
}
else if ((rec_pidl.frame_id_and_parity.frame_id == 0x3c)&&(lin_slave_buffer.data[0] == 0))
{ // 接收到休眠命令
timerRA_rcv_wakeup_config(); // timerRA接收wakeup初始化
lin_cmd = CMD_SLEEP; // 进入休眠
sleep_status = SLEEP_DUMMY;
}
else // 校验和无误时
{ // 将接收到的数据放到id匹配的slot中
lp_slot_comm = 0;
while(lp_slot_comm < 3)
{
if(lin_slave_slot[lp_slot_comm].slot_id == rec_pidl.frame_id_and_parity.frame_id)
{
for(lp_data_comm = 0; lp_data_comm < dlc_convert[rec_pidl.pid_str.dlc]; lp_data_comm ++)
{
lin_slave_slot[lp_slot_comm].data[lp_data_comm] = lin_slave_buffer.data[lp_data_comm];
}
lp_slot_comm = 10; // 结束while循环
}
else
{
lp_slot_comm ++;
}
}
timerRA_rcv_break_config(); // 帧接收完毕,timerRA接收break初始化
timerRB_4s_counter = 0U; // 4s计数器开始计数
lin_cmd = CMD_IDLE; // 进入idle状态
idle_status = IDLE_DUMMY;
}
}
}
else
{
frame_30ms_timeout_test(); // 9600比特/s的情况下,30ms超时检测
}
break;
case RUN_TX_CHECKSUM: // 进入发送校验和子状态
if(ir_s0tic == YES) // 发送完毕
{
ir_s0tic = NO; // 清零标志
te_u0c1 = LDIS; // 禁止uart发送
timerRA_rcv_break_config(); // timerRA接收break初始化
timerRB_4s_counter = 0U; // 4s计数器开始计数
lin_cmd = CMD_IDLE; // 进入IDLE状态
idle_status = IDLE_DUMMY;
}
else
{
}
break;
default:
break;
}
}
/*------------------------------------------------------
名称 : uart_error_test
功能 : uart接收错误检测函数
入口 : 待检测uart高位字节
出口 : 无
调用 : 无
寄存器 : 无
------------------------------------------------------*/
void uart_error_test(uchar8 uart_h)
{
if((uart_h & 0x80U) == 0x80U) // 错误总计数
{
if((uart_h & 0x10U) == 0x10U) // uart传输错误
{
lin_cmd = CMD_ERROR; // 进入错误状态
error_code = UART_FRAMING_ERROR; // 错误代码UART_FRAMING_ERROR
}
else
{
}
if((uart_h & 0x20U) == 0x20U) // uart奇偶校验错误
{
lin_cmd = CMD_ERROR; // 进入错误状态
error_code = UART_PARITY_ERROR; // 错误代码UART_PARITY_ERROR
}
else
{
}
if((uart_h & 0x40U) == 0x40U) // uart overrun错误
{
lin_cmd = CMD_ERROR; // 进入错误状态
error_code = UART_OVERRUN_ERROR; // 错误代码UART_OVERRUN_ERROR
}
else
{
}
}
else // 没有错误退出
{
}
}
/*------------------------------------------------------
名称 : uart_init
功能 : uart初始化
入口 : 无
出口 : 无
调用 : 无
寄存器 : uart相关
------------------------------------------------------*/
void uart_init(void)
{
smd2_u0mr = 1; // UART模式发送8bit数据
smd1_u0mr = 0;
smd0_u0mr = 1;
ckdir_u0mr = 0; // 采用内部时钟
stps_u0mr = 0; // 1 停止位
prye_u0mr = LOFF; // 不用奇偶校验
// 选择f1
clk1_u0c0 = 0;
clk0_u0c0 = 0;
nch_u0c0 = 0; // TXD0 pin CMOS输出
ckpol_u0c0 = 1; // 上升沿发送数据,下降沿接收数据
uform_u0c0 = 0; // LSB
u0irs_u0c1 = 1; // 发送中断时机:发送完毕
u0rrm_u0c1 = 0; // 不用连续接收模式
// initial: baud rate 20M/(9600*16) = 130
u0brg = INIT_UART0_BITRATE - 1; // UART波特率设置
}
/*------------------------------------------------------
名称 : frame_30ms_timeout_test
功能 : 帧接收数据超时检测,时限为30ms,9600比特/s时
入口 : 无
出口 : 无
调用 : 无
寄存器 : 无
------------------------------------------------------*/
void frame_30ms_timeout_test(void)
{
if(timerRB_10ms_counter >= 3U) // 超过30ms
{
lin_cmd = CMD_ERROR; // 进入错误状态
error_code = SHORT_MESSAGE_ERROR; // 错误状态 SHORT_MESSAGE_ERROR
}
else // 等待
{
}
}
/*------------------------------------------------------
名称 : timerRA_rcv_wakeup_config
功能 : timerRA判断准备接收wakeup信号(显性电平持续至少150us)的初始化工作
入口 : 无
出口 : 无
调用 : 无
寄存器 : timerRA相关
------------------------------------------------------*/
void timerRA_rcv_wakeup_config(void)
{
line_lincr = LOFF; // 停止LIN模块,必须
while(line_lincr == HON) // 确认LIN模块工作停止
{
}
tstop_tracr = HEN; // 强制timerRA终止
while(tcstf_tracr == HON) // 等待timerRA直到计数停止
{
}
ir_traic = NO; // 清零标志位
tundf_tracr = NO;
tedgf_tracr = NO;
tedgsel_traioc = 0; // 脉冲始于低电平
topcr_traioc = 0; // 该模式下设为0
toena_traioc = 0;
tiosel_traioc = 1; // p1_5 作为traio
pd1_5 = PPORT_INPUT; // RxD0引脚信号方向设为输入
tipf1_traioc = LDIS; // 无需filter
tipf0_traioc = LDIS;
tmod2_tramr = 0; // TMOD2-TMOD0: 011 脉冲宽度测量模式
tmod1_tramr = 1;
tmod0_tramr = 1;
tck2_tramr = 0; // f1
tck1_tramr = 0;
tck0_tramr = 0;
tckcut_tramr = 0; // 提供timerRA计数源
//150us: 20MHz/(f1*150*20) = 150us
trapre = 150 - 1;
tra = 20 - 1;
tstart_tracr = HON; // 启动timerRA
}
/*------------------------------------------------------
名称 : timerRA_snd_wakeup_config
功能 : timerRA发送wakeup信号(显性电平持续至少250us)的初始化工作
入口 : 无
出口 : 无
调用 : 无
寄存器 : timerRA相关
------------------------------------------------------*/
void timerRA_snd_wakeup_config(void)
{
line_lincr = LOFF; // 停止LIN模块,必须
while(line_lincr == HON) // 确认LIN模块工作停止
{
}
tstop_tracr = HEN; // 强制timerRA终止/LIN flow
while(tcstf_tracr == HON) // 等待timerRA直到计数停止
{
}
ir_traic = NO; // 清零标志位
tundf_tracr = NO;
tedgf_tracr = NO;
traioc = 0; // 定时器模式下该寄存器为0
tmod2_tramr = 0; // TMOD2-TMOD0: 000 定时器模式
tmod1_tramr = 0;
tmod0_tramr = 0;
tck2_tramr = 0; // f1
tck1_tramr = 0;
tck0_tramr = 0;
tckcut_tramr = 0; // 提供timerRA计数源
//250us: 20MHz/(f1*250*20) = 250us
trapre = 250 - 1;
tra = 20 - 1;
p1_5 = PPORT_HIGH; // p1_5输出高电平
pd1_5 = PPORT_OUTPUT;
tstart_tracr = HON; // 启动timerRA
p1_5 = PPORT_LOW; // 一旦timerRA开始计数,引脚p1_5开始输出低电平
}
/*------------------------------------------------------
名称 : timerRA_rcv_break_config
功能 : timerRA接收break信号(判断显性电平持续至少11bit)的初始化工作
入口 : 无
出口 : 无
调用 : 无
寄存器 : timerRA,LIN相关
------------------------------------------------------*/
void timerRA_rcv_break_config(void)
{
tstop_tracr = HOFF; // 强制timerRA终止/LIN flow
while(tcstf_tracr == HON) // 等待timerRA直到计数停止
{
}
ir_traic = NO; // 清零标志位
tundf_tracr = NO;
tedgf_tracr = NO;
pd1_5 = PPORT_INPUT; // p1_5输入
tedgsel_traioc = 0; // 脉冲开始为低电平/LIN flow
topcr_traioc = 0; // 忽略
toena_traioc = 0;
tiosel_traioc = 1; // p1_5 作为traio/LIN flow
tipf1_traioc = 0; // 忽略
tipf0_traioc = 0;
// TMOD2-TMOD0: 011,脉冲宽度测量模式/LIN flow
tmod2_tramr = 0;
tmod1_tramr = 1;
tmod0_tramr = 1;
//f1/LIN flow
tck2_tramr = 0;
tck1_tramr = 0;
tck0_tramr = 0;
tckcut_tramr = 0; // 忽略
// 测试break宽度 20M*11/9600=90*256, break宽度11 bits./LIN flow
trapre = TRAPRE_BREAKTEST - 1U; //256-1
tra = TRA_BREAKTEST - 1U;
line_lincr = HON; // 启动LIN功能
mst_lincr = 0; // 从机模式
sbe_lincr = 0; // 在检测到break后去掉RxD0屏蔽
// 将LIN模块支持的三个利用timerRA的中断关掉;若用户希望利用中断处理,需要使能以下。
bcie_lincr = LDIS; // 总线冲突检测中断关掉,该sample为了简化,没有作总线冲突检测
sbie_lincr = LDIS; // 检测到break时发出的中断关掉,该sample用查询
sfie_lincr = LDIS; // 测量完同步段(Sync)时发出的中断关掉(只应用于从机),该sample用查询
// 清除状态标志
b2clr_linst = HON; // BCDCT 总线冲突检测标志位清零
b1clr_linst = HON; // 检测到break的标志位清零
b0clr_linst = HON; // 测量完同步段(Sync)的标志位清零
tstart_tracr = HON; // 启动timerRA
while(tcstf_tracr != HON) // 确认timerRA启动
{
}
lstart_lincr = HOFF; // 禁止UART接收/ LIN FLOW
while(rxdsf_lincr == LON) // 确认uart接收禁止
{
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -