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

📄 lin_master.c

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