⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lin_slave.c

📁 基于LPC76X的LIN开发通信源程序调试通过
💻 C
📖 第 1 页 / 共 2 页
字号:
				}
			}
			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 + -