ISO15765-4 协议 汽车ECU系统模拟

本文详细介绍了如何使用STM32通过USART和CAN通信协议模拟ISO15765-4协议,涉及串口通信参数配置、CAN总线工作原理、中断处理和实际操作中的AT指令应用。代码示例展示了实现过程。
摘要由CSDN通过智能技术生成

ISO15765-4 协议 汽车ECU系统模拟

本节介绍的代码量比较多,用到的知识也比较丰富,篇幅较长!
看完这篇文章能够掌握的知识包括:ISO15765-4协议、USART串口通信协议、CAN通信协议、中断等。

一、USART串口通信

串口通信:串口按位(bit)发送和接收字节。
参数包括:波特率、数据位、停止位和奇偶校验位。对于两个进行通信的端口,这些参数必须匹配。
波特率:即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps。
数据位:一个数据包的位数。一般为8位,也就是一个字节。
停止位:用于表示单个包的最后一位。典型的值为1,1.5和2位。停止位越长,通信速度越慢。
奇偶校验位:用一个值确保传输的数据有偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。
代码如下:

/************************************************************************
  * @描述:  串口配置
  * @参数:  Baud:串口波特率
  * @返回值: None
  **********************************************************************/
void PC_USART_Config(u32 Baud)
{
    	GPIO_InitTypeDef GPIO_InitStructure; 	//声明GPIO结构体
		USART_InitTypeDef USART_InitStructure;	//声明USART结构体
    
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
	
		//USART1_TX   GPIOA.9
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 				//PA.9
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;			//复用推挽输出
		GPIO_Init(GPIOA, &GPIO_InitStructure);					//初始化GPIOA.9
   
		//USART1_RX	  GPIOA.10初始化
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;				//PA10
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//浮空输入
		GPIO_Init(GPIOA, &GPIO_InitStructure);					//初始化GPIOA.10  

		//USART 初始化设置
		USART_InitStructure.USART_BaudRate = Baud;		//串口波特率
		USART_InitStructure.USART_WordLength = USART_WordLength_8b;	//字长为8位数据格式
		USART_InitStructure.USART_StopBits = USART_StopBits_1;			//一个停止位
		USART_InitStructure.USART_Parity = USART_Parity_No;		//无奇偶校验位
		USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
		USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

    	USART_Init(USART1, &USART_InitStructure); 		//初始化串口1
		USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);	//开启串口接受中断
		USART_Cmd(USART1, ENABLE);                    	//使能串口1 
}
//映射printf()函数,用来串口调试/发AT指令
#if 1
#pragma import(__use_no_semihosting)

struct __FILE
{
    int handle;
    /* Whatever you require here. If the only file you are using is */
    /* standard output using printf() for debugging, no file handling */
    /* is required. */
};
/* FILE is typedef’ d in stdio.h. */
FILE __stdout;
_sys_exit(int x)
{
    x = x;
}
int fputc(int ch, FILE *f)
{
    while((USART1->SR&0x40) == 0);
    USART1->DR = (u8)ch;
    return ch;
}
#endif

我使用的是PA9\PA10 IO口

二、CAN通信协议

这部分内容较多,是我从百度百科上面选择性复制过来的。需要从代码中对照下面的原理进行理解。说实话,里面的细节我也不是很清楚,会用就是硬理!!!
工作原理:CAN总线使用串行数据传输方式,可以1Mb/s的速率在40m的双绞线上运行,也可以使用光缆连接,而且在这种总线上总线协议支持多主控制器。CAN与I2C总线的许多细节很类似,但也有一些明显的区别。当CAN总线上的一个节点(站)发送数据时,它以报文形式广播给网络中所有节点。对每个节点来说,无论数据是否是发给自己的,都对其进行接收。每组报文开头的11位字符为标识符,定义了报文的优先级,在同一系统中标识符是唯一的。当几个站同时竞争总线读取时,这种配置十分重要。
当一个站要向其它站发送数据时,该站的CPU将要发送的数据和自己的标识符传送给本站的CAN芯片,并处于准备状态;当它收到总线分配时,转为发送报文状态。CAN芯片将数据根据协议组织成一定的报文格式发出,这时网上的其它站处于接收状态。每个处于接收状态的站对接收到的报文进行检测,判断这些报文是否是发给自己的,以确定是否接收它。由于CAN总线是一种面向内容的编址方案,因此很容易建立高水准的控制系统并灵活地进行配置。我们可以很容易地在CAN总线中加进一些新站而无需在硬件或软件上进行修改。当所提供的新站是纯数据接收设备时,数据传输协议不要求独立的部分有物理目的地址。它允许分布过程同步化,即总线上控制器需要测量数据时,可由网上获得,而无须每个控制器都有自己独立的传感器。
CAN总线的特点:
(1)具有实时性强、传输距离较远、抗电磁干扰能力强、成本低等优点;
(2)采用双线串行通信方式,检错能力强,可在高噪声干扰环境中工作;
(3)具有优先权和仲裁功能,多个控制模块通过CAN 控制器挂到CAN-bus 上,形成多主机局部网络;
(4)可根据报文的ID决定接收或屏蔽该报文;
(5)可靠的错误处理和检错机制;
(6)发送的信息遭到破坏后,可自动重发;
(7)节点在错误严重的情况下具有自动退出总线的功能;
(8)报文不包含源地址或目标地址,仅用标志符来指示功能信息、优先级信息。
报文类型:
在CAN2.0B的版本协议中有两种不同的帧格式,不同之处为标识符域的长度不同,含有11位标识符的帧称之为标准帧,而含有29位标识符的帧称为扩展帧。
帧类型:
在报文传输时,不同的帧具有不同的传输结构,下面将分别介绍四种传输帧的结构,只有严格按照该结构进行帧的传输,才能被节点正确接收和发送。
(1)数据帧由七种不同的位域(Bit Field)组成:帧起始(Start of )、仲裁域(Arbitration Field)、控制域(Control Field)、数据域(DataField)、CRC域(CRC Field)、应答域(ACK Field)和帧结尾(End of )。数据域的长度可以为0~8个字节。
1)帧起始(SOF):帧起始(SOF)标志着数据帧和远程帧的起始,**仅由一个“显性”位组成。**在CAN的同步规则中,当总线空闲时(处于隐性状态),才允许站点开始发送(信号)。所有的站点必须同步于首先开始发送报文的站点的帧起始前沿(该方式称为“硬同步”)。
2)仲裁域:仲裁域由标识符和RTR位组成,标准帧格式与扩展帧格式的仲裁域格式不同。标准格式里,仲裁域由1l位标识符和RTR位组成。标识符位有ID28~IDl8。扩展帧格式里,仲裁域包括29位标识符、SRR位、IDE(Identifier Extension,标志符扩展)位、RTR位。其标识符有ID28~IDO。为了区别标准帧格式和扩展帧格式,CANl.0~1.2版本协议的保留位r1现表示为IDE位。IDE位为显性,表示数据帧为标准格式;IDE位为隐性,表示数据帧为扩展帧格式。在扩展帧中,替代远程请求(Substitute Remote Request,SRR)位为隐性。仲裁域传输顺序为从最高位到最低位,其中最高7位不能全为零。RTR的全称为“远程发送请求(Remote TransmissionRequest)”。RTR位在数据帧里必须为“显性”,而在远程帧里必须为“隐性”。它是区别数据帧和远程帧的标志。
3)控制域:控制域由6位组成,包括2个保留位(r0、r1同于CAN总线协议扩展)及4位数据长度码,允许的数据长度值为0~8字节。
4)数据域:发送缓冲区中的数据按照长度代码指示长度发送。对于接收的数据,同样如此。它可为0~8字节,每个字节包含8位,首先发送的是MSB(最高位)。
5)CRC校验码域:它由CRC域(15位)及CRC边界符(一个隐性位)组成。CRC计算中,被除的多项式包括帧的起始域、仲裁域、控制域、数据域及15位为0的解除填充的位流给定。此多项式被下列多项式X15+X14+X10+X8+X7+X4+X3+1除(系数按模2计算),相除的余数即为发至总线的CRC序列。发送时,CRC序列的最高有效位被首先发送/接收。之所以选用这种帧校验方式,是由于这种CRC校验码对于少于127位的帧是最佳的。
6)应答域:应答域由发送方发出的两个(应答间隙及应答界定)隐性位组成,所有接收到正确的CRC序列的节点将在发送节点的应答间隙上将发送的这一隐性位改写为显性位。因此,发送节点将一直监视总线信号已确认网络中至少一个节点正确地接收到所发信息。应答界定符是应答域中第二个隐性位,由此可见,应答间隙两边有两个隐性位:CRC域和应答界定位。
7)帧结束域:每一个数据帧或远程帧均由一串七个隐性位的帧结束域结尾。这样,接收节点可以正确检测到一个帧的传输结束。
代码如下:

/************************************************************************
  * @描述:  CAN配置
  * @参数:  id1:标识码高位
  * 			  id2:标识码低位
  *				  mid1:屏蔽码高位
  * 			  mid2:屏蔽码低位
  * 			  velocity:波特率 = Fpclk1/((CAN_BS1_11tq+1+CAN_BS2_6tq+1+1)*velocity);
  * @返回值: 0
  **********************************************************************/
u8 CAN_Mode_Init(u32 id1, u32 id2, u32 mid1, u32 mid2, u16 velocity)
{
	GPIO_InitTypeDef 			GPIO_InitStructure; 
	CAN_InitTypeDef       	CAN_InitStructure;
 	CAN_FilterInitTypeDef 	CAN_FilterInitStructure;
#if CAN_RX0_INT_ENABLE 
   	NVIC_InitTypeDef  NVIC_InitStructure; //声明中断结构体
#endif
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);//使能PORTA时钟	                   											 
  	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟	
	
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;		//PA12 TX
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽
    GPIO_Init(GPIOA, &GPIO_InitStructure);			//初始化IO
   
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;				//PA11 RX
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//上拉输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);					//初始化IO
	  
 	//CAN单元设置
 	CAN_InitStructure.CAN_TTCM=DISABLE;		//非时间触发通信模式
 	CAN_InitStructure.CAN_ABOM=DISABLE;		//软件自动离线管理
  	CAN_InitStructure.CAN_AWUM=DISABLE;		//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)//
  	CAN_InitStructure.CAN_NART=ENABLE;		//使能报文自动传送
  	CAN_InitStructure.CAN_RFLM=DISABLE;		//报文不锁定,新的覆盖旧的 
  	CAN_InitStructure.CAN_TXFP=DISABLE;		//优先级由报文标识符决定 
  	CAN_InitStructure.CAN_Mode= CAN_Mode_Normal;	//模式设置: mode:0,普通模式;1,回环模式; //
  	//设置波特率
  	CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;	
  	CAN_InitStructure.CAN_BS1=CAN_BS1_11tq; 
  	CAN_InitStructure.CAN_BS2=CAN_BS2_6tq;
  	CAN_InitStructure.CAN_Prescaler=velocity;      //配置通信速度
  	CAN_Init(CAN1, &CAN_InitStructure);            // 初始化CAN1 

 	CAN_FilterInitStructure.CAN_FilterNumber=0;	  					//过滤器0
   	CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;	//屏蔽位模式
  	CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; 	//32位 
  	CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5;
  	CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5;
  	CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mid1<<5;
  	CAN_FilterInitStructure.CAN_FilterMaskIdLow=mid2<<5;
  	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
 	CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0

  	CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
	CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
	return 0;
}   

三、中断

中断流程:当主程序在运行时,接收到一个中断请求,此时CPU会保存当前程序的运行状态(如:堆栈、寄存器的值等),然后进入中断服务程序。当中断服务程序运行结束后,CPU继续运行当前代码。
中断配置过程中最重要的是中断优先级,其中包括:抢占优先级和响应优先级。抢占优先级占主导地位,当两个中断服务程序抢占优先级一样时,再比较响应优先级。
程序中使用了定时器中断服务函数,所以需先配置定时器相关参数
中断配置及中断服务程序如下:

/************************************************************************
  * @描述:  定时器2配置
  * @参数:   T2Delayms
  * 				时钟计算公式:Tout = ((arr+1)*(T2Delayms+1))/Tclk
  * 				这里的arr为35999
  * @返回值: NONE
  **********************************************************************/
void TIM2_Config(u32 T2Delayms)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    TIM_TimeBaseStructure.TIM_Period = 35999;
    TIM_TimeBaseStructure.TIM_Prescaler = T2Delayms;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    TIM_ARRPreloadConfig(TIM2, DISABLE);
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM2, ENABLE);
}
/************************************************************************
  * @描述:  中断配置
  * @参数:  None
  * @返回值: None
  **********************************************************************/
void NVIC_Config(void)
{
    NVIC_InitTypeDef  NVIC_InitStructure;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //中断优先级分组

    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; 			//配置定时器中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 			//响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//中断使能
    NVIC_Init(&NVIC_InitStructure);
	//配置CAN中断
    NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
	//配置串口中断
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

下面是三个中断服务程序:

/************************************************************************
  * @描述:  USART中断服务函数
  * @参数:  None
  * @功能:  实现ISO15765-4协议 部分AT指令,AT指令通过串口发送
  * @返回值: None
  **********************************************************************/
v
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值