📄 lin_master.c
字号:
cur_processing_data ++; // 当前处理数据 +1
break;
// command = 2,主机接收从从机发送来的数据
case 0x02:
run_status = RUN_RX_DATA; // 主机转入接收数据段的状态
re_u0c1 = HEN; // uart接收允许
ir_s0ric = NO; // uart接收中断查询标志清零
cur_processing_data = 0;
break;
// command = 3,主机忽略从从机发送来的数据
case 0x03:
lin_frm.bit.complete = YES; // 帧处理完成标志置1
break;
// 此处可添加其它命令 case 0,case 4 ~ 15,
// 当dlc = 11时,case 12~15 按照LIN协议规定有特殊用途
default:
break;
}
}
else // 等待发送完毕
{
}
break;
case RUN_TX_DATA: // 进入发送数据段状态
if(ir_s0tic == YES) // 判断data0是否已发送完毕
{
ir_s0tic = NO; // 发送完毕,将该标志清零
// 若数据未发送完毕
if(cur_processing_data < dlc_convert[lin_buffer.lin_slot[lin_frm.bit.cur_frm].pid.pid_str.dlc])
{
// 将下一个数据发到发送buffer中
u0tbl = lin_buffer.lin_slot[lin_frm.bit.cur_frm].data[cur_processing_data];
cur_processing_data ++; // 当前处理的数据 +1
}
else
{
cur_processing_data = 0; // 清零当前正在处理的数据
// 将校验和字段装入发送buffer中
u0tbl = lin_buffer.lin_slot[lin_frm.bit.cur_frm].checksum;
run_status = RUN_TX_CHECKSUM; // 转入发送校验和字段的状态
}
}
else // 等待发送完毕
{
}
break;
case RUN_RX_DATA: // 进入接收数据段的状态
if(ir_s0ric == YES) // 判断是否已有数据装入到uart接收buffer中
{
ir_s0ric = NO; // 清零uart接收中断查询标志
// 若数据未接收完毕
if(cur_processing_data < dlc_convert[lin_buffer.lin_slot[lin_frm.bit.cur_frm].pid.pid_str.dlc])
{
// 接收uart低位字节
lin_buffer.lin_slot[lin_frm.bit.cur_frm].data[cur_processing_data] = u0rbl;
uarth_error_buf = u0rbh; // 接收高位字节
uart_error_test(uarth_error_buf); // 调用uart接收错误检测函数
cur_processing_data ++; // 当前处理的数据 +1
}
else
{
// 接收校验和
lin_buffer.lin_slot[lin_frm.bit.cur_frm].checksum = u0rbl;
uarth_error_buf = u0rbh;
uart_error_test(uarth_error_buf); // 调用uart接收错误检测函数
// 禁止uart接收,必须
re_u0c1 = LDIS;
// 重新计算校验和,方法同上,通过本地接收到的数据计算校验和时不用将结果取反
lp_data_comm = 0;
local_checksum = 0;
lp_dlc_comm = dlc_convert[lin_buffer.lin_slot[lin_frm.bit.cur_frm].pid.pid_str.dlc];
while(lp_dlc_comm > 0)
{
if ((uint16)local_checksum + lin_buffer.lin_slot[lin_frm.bit.cur_frm].data[lp_data_comm] >= 256U)
{
local_checksum += lin_buffer.lin_slot[lin_frm.bit.cur_frm].data[lp_data_comm];
local_checksum ++;
}
else
{
local_checksum += lin_buffer.lin_slot[lin_frm.bit.cur_frm].data[lp_data_comm];
}
lp_data_comm ++;
lp_dlc_comm --;
}
// 若接收到的校验和与本地计算的校验和做加法后不等于0xff,则传输数据有误
if(local_checksum + lin_buffer.lin_slot[lin_frm.bit.cur_frm].checksum != (uchar8)0xff)
{
lin_cmd = CMD_ERROR; // 程序进入错误状态
error_code = LINRX_CHECKSUM_ERROR; // 错误代码:校验和错误
}
else
{
lin_frm.bit.complete = YES; // 校验和无误,该frame处理完毕
}
}
}
else // 等待接收数据段及校验和字段
{
frame_30ms_timeout_test(); // 调用超时检测程序
}
break;
case RUN_TX_CHECKSUM: // 进入发送校验和状态
if(ir_s0tic == YES) // 判断校验和是否已发送完毕
{
ir_s0tic = NO; // 发送完毕,将该标志清零
lin_frm.bit.complete = YES; // 该frame处理完毕
}
else // 等待发送完毕
{
}
break;
default:
break;
}
// 帧时隙为20ms,当当前帧传输完毕,等到计时达到20ms时
if ((lin_frm.bit.complete == YES)&&(timerRB_10ms_counter >= 2U))
{
lin_frm.bit.complete = NO; // 清零帧处理完毕标志
lin_frm.bit.cur_frm ++; // 进入下个帧
run_status = RUN_IDLE; // 进入运行期的idle状态,当前frame处理完毕
}
else // 等待,直到20ms
{
}
}
/*------------------------------------------------------
名称 : idle_processing
功能 : idle状态处理函数,当前进度表处理完毕后
一旦发现总线上出现显性电平,将4s计数器清零
否则,大于4s系统将进入休眠状态
入口 : 无
出口 : 无
调用 : void timerRA_rcv_wakeup_config(void)
寄存器 : 无
------------------------------------------------------*/
void idle_processing(void)
{
if(p1_5 == PPORT_LOW) // 若总线上出现显性电平,则4s进入休眠状态重新计算
{
timerRB_4s_counter = 0U; // 清零计数器
}
else if(timerRB_4s_counter >= 400U) // 如果到达了4s
{
timerRA_rcv_wakeup_config(); // timerRA准备接收wakeup信号初始化
lin_cmd = CMD_SLEEP; // 进入休眠状态
sleep_status = SLEEP_RCV_WAKEUP;
}
else // 等待4s
{
}
}
/*------------------------------------------------------
名称 : 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 = LDIS; // 不用奇偶校验
// 选择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 = LDIS; // 不用连续接收模式
// baud rate 20M/(9600*16) = 130
u0brg = INIT_UART0_BITRATE - 1; // UART波特率设置
}
/*------------------------------------------------------
名称 : 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, TxD0 引脚信号方向设为输入
pd1_4 = PPORT_INPUT;
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;
re_u0c1 = LDIS; // UART发送/接收禁止
te_u0c1 = LDIS;
tstart_tracr = HON; // 启动timerRA
}
/*------------------------------------------------------
名称 : timerRA_snd_break_config
功能 : timerRA发送break信号(显性电平持续至少13bit)的初始化工作
入口 : 无
出口 : 无
调用 : 无
寄存器 : timerRA及LIN相关
------------------------------------------------------*/
void timerRA_snd_break_config(void)
{
tstop_tracr = HEN; // 强制timerRA终止/LIN 流程
while(tcstf_tracr == HON) // 等待timerRA直到计数停止
{
}
tedgsel_traioc = 1; // 脉冲始于低电平/LIN 流程
topcr_traioc = 0; // 忽略
toena_traioc = 0;
tiosel_traioc = 1; // p1_5 作为traio/LIN 流程
tipf1_traioc = 0; // 忽略
tipf0_traioc = 0;
tmod2_tramr = 0; // TMOD2-TMOD0: 000, 定时器模式/LIN 流程
tmod1_tramr = 0;
tmod0_tramr = 0;
tck2_tramr = 0; // f1/LIN 流程
tck1_tramr = 0;
tck0_tramr = 0;
tckcut_tramr = 0; // 忽略
// break width 20M*13/9600=106*256, break width 13 bits./LIN 流程
trapre = 256 - 1; //256-1
tra = 106 - 1;
line_lincr = HON; // 启动硬件LIN模块
mst_lincr = 1; // 主机模式
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
}
/*------------------------------------------------------
名称 : 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_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 流程
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) = 1/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开始输出低电平
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -