芯旺微 KF32A156/KF32A150系列chipon 32位机的LIN总线使用基础

本文介绍了KF32A156系列(包括KF32A146/KF32A136)微控制器的LIN模块配置,包括IO口、串口和中断的设置,以及主机和从机任务的差异。LIN帧结构由间隔场、同步场、ID场、数据场和校验场组成。文章提供了主机和从机的配置示例,如串口配置、中断配置和DMA设置,并强调了在发送间隔场时使用定时器的重要性。
摘要由CSDN通过智能技术生成

申明:原创扣字不易,转载请注明源出处!!!
hello大家好,今天主要来说KF32A156系列(包括KF32A146/KF32A136)的LIN模块的配置(这里均已A02版本为准)。
首先要说明的是:LIN是通过串口来支持的,也就是串口能够发出支持lin协议的相关操作。

至于lin帧的格式和协议,这个网上其他资料较多,此处不作详细说明,可参考下图:
在这里插入图片描述
这里主要说一下lin帧的组成:间隔场 - 同步场 - ID场 - 数据场 - 校验场

主机任务:间隔场 - 同步场 - ID场 - 数据场 - 校验场 ;间隔场 - 同步场 - ID场 。
从机任务:数据场 - 校验场 。

lin任务:主机任务 , 从机任务

lin主机配置

主机:可执行 主机任务 和 从机任务
配置外设的三步走:IO口配置 ,usart模块配置 ,配置相关中断
这里就和官方例程保持同步,以串口5映射到为例说明

io口配置:配置io口为重映射模式,再重映射为串口,函数代码如下

void LIN_UASRT_GPIO_INIT()
{
	GPIO_Write_Mode_Bits (GPIOA_SFR,GPIO_PIN_MASK_7, GPIO_MODE_RMP);
	GPIO_Write_Mode_Bits (GPIOA_SFR,GPIO_PIN_MASK_8, GPIO_MODE_RMP);
	GPIO_Pin_RMP_Config(GPIOA_SFR, GPIO_Pin_Num_7, GPIO_RMP_AF13);
	GPIO_Pin_RMP_Config(GPIOA_SFR, GPIO_Pin_Num_8, GPIO_RMP_AF13);
}

串口配置:外设配置

void USART_LIN_config(USART_SFRmap *USARTx)
{
	USART_InitTypeDef USART_InitStructure;

	/* Reset and enable USARTx */
	USART_Reset(USARTx); 
	/* configure USARTx to LIN mode */
	USART_Struct_Init(&USART_InitStructure);
    USART_InitStructure.m_Mode=USART_MODE_FULLDUPLEXASY;                      
    USART_InitStructure.m_TransferDir=USART_DIRECTION_FULL_DUPLEX;             
    USART_InitStructure.m_WordLength=USART_WORDLENGTH_8B;                     
    USART_InitStructure.m_StopBits=USART_STOPBITS_1;                           
    USART_InitStructure.m_BaudRateBRCKS=USART_CLK_HFCLK;                       
    USART_InitStructure.m_BRAutoDetect=USART_ABRDEN_OFF;
    /** Use 16M clock as an example to list the following baud rates 
	 * 	4800    z:208    x:0    y:0
	 * 	9600    z:104    x:0    y:0
	 * 	19200   z:52     x:0    y:0
	 * 	115200  z:8      x:1    y:13
	*/
	/* Integer part z, get value range is 0 ~ 0xFFFF */
    USART_InitStructure.m_BaudRateInteger=52;
	/* Numerator part x, get value range is 0 ~ 0x0f */
    USART_InitStructure.m_BaudRateNumerator=0;
	/* Denominator part y, get value range is 0 ~ 0x0f */
    USART_InitStructure.m_BaudRateDenominator=0;
	USART_Configuration(USARTx,&USART_InitStructure);
	/* Enable receive interrupt */
	USART_RDR_INT_Enable(USARTx,TRUE);	
	/* Enable LIN moudle */
	USART_RESHD_Enable (USARTx, TRUE);					
	USART_Cmd(USARTx,TRUE);                             	
}

中断配置:刚刚在串口初始化的已经将接收中断开启,那么接下来要开启串口中断

	INT_Interrupt_Enable(INT_USART5, TRUE);    //开启串口5中断
	//下面两行代码可忽略,仅是中断相关配置
	INT_Interrupt_Priority_Config(INT_USART5, 7, 1);	
	/* Configure interrupt priority group, default is 3VS1 */
	INT_Priority_Group_Config(INT_PRIORITY_GROUP_3VS1);    

发送数据:注意这里发送间隔场的时候需要用到定时器来延时

//我们就用基本定时器T14用来延时,周期值可根据波特率自行配置,需要至少13个延时
TIM_Reset(T14_SFR);			//定时器外设复位,使能外设时钟
BTIM_Work_Mode_Config(T14_SFR,BTIM_TIMER_MODE);		//定时模式选择
BTIM_Set_Counter(T14_SFR,0);				//定时器计数值
BTIM_Set_Period(T14_SFR,21632);				//定时器周期值
BTIM_Set_Prescaler(T14_SFR,0);			 //定时器预分频值0+1=1(不分频)
BTIM_Clock_Config(T14_SFR,BTIM_HFCLK);    //选用HFCLK时钟
BTIM_Counter_Mode_Config(T14_SFR,BTIM_COUNT_UP_OF);	//向上计数,上溢产生中断标志


//发送接口函数  这里已经做好,如果是主机收的情况下,不再发送校验场
//参数:串口号;从机id;数据;数据个数 
void LIN_Send(USART_SFRmap* USARTx, uint8_t SlaveID, uint8_t* Databuf, uint32_t Length)
{
	/* Calculate the protection data */
	uint8_t ProtectID = GetParityValue(SlaveID);
	/* Calculate the checksum data */
	uint8_t CheckVaule = GetCheckSumValue(ProtectID, Databuf, Length);

	USART_Send_Blank_Enable(USARTx,TRUE);						//使能发送间隔
	BTIM_Clear_Overflow_INT_Flag (T14_SFR);						//清T14溢出中断标志位
	BTIM_Set_Counter(T14_SFR,0);								//定时器计数值清0
	BTIM_Cmd(T14_SFR,TRUE);										//定时器启动控制使能
	while(!BTIM_Get_Overflow_INT_Flag(T14_SFR));				//等待定时
	USART_Send_Blank_Enable(USARTx,FALSE);						//清发送间隔
	BTIM_Cmd(T14_SFR,FALSE);									//定时器关闭
	USART_SendData(USARTx,0x55);							    //设置同步码
	/* Send Protected ID */
	USART_SendData(USARTx, ProtectID);
	/* Send user data */
	for (uint8_t i = 0; i < Length; i++)
	{
		USART_SendData(USARTx, Databuf[i]);
	}
	/* Send checksum data */
	if(Length)
	{
		USART_SendData(USARTx, CheckVaule);
	}
}

ok,至此主机写说完,只需要调用LIN_Send函数传入所需参数即可。这里不再详细说明主机读的过程,由于开启了接收中断,故而主机读相当于串口接收数据的过程。在中断接收即可。

lin从机配置

这里同样为了保持和官方例程一致的,我们也在从机发送的过程中使用DMA传输数据
,这里不再赘述io口配置,请参考主机的部分。

**串口配置:**做为从机的话,要打开接收中断和间隔场中断,以及使能DMA传输

void USART_LIN_config(USART_SFRmap *USARTx)
{
	USART_InitTypeDef USART_InitStructure;

	/* Reset and enable USARTx */
	USART_Reset(USARTx);
	/* configure USARTx to LIN mode */
	USART_Struct_Init(&USART_InitStructure);
	USART_InitStructure.m_Mode = USART_MODE_FULLDUPLEXASY;
	USART_InitStructure.m_TransferDir = USART_DIRECTION_FULL_DUPLEX;
	USART_InitStructure.m_WordLength = USART_WORDLENGTH_8B;
	USART_InitStructure.m_StopBits = USART_STOPBITS_1;
	USART_InitStructure.m_BaudRateBRCKS = USART_CLK_HFCLK;
	USART_InitStructure.m_BRAutoDetect = USART_ABRDEN_OFF;
	/** Use 16M clock as an example to list the following baud rates
	 * 	4800    z:208    x:0    y:0
	 * 	9600    z:104    x:0    y:0
	 * 	19200   z:52     x:0    y:0
	 * 	115200  z:8      x:1    y:13
	 */
	/* Integer part z, get value range is 0 ~ 0xFFFF */
	USART_InitStructure.m_BaudRateInteger = 52;
	/* Numerator part x, get value range is 0 ~ 0x0f */
	USART_InitStructure.m_BaudRateNumerator = 0;
	/* Denominator part y, get value range is 0 ~ 0x0f */
	USART_InitStructure.m_BaudRateDenominator = 0;
	USART_Configuration(USARTx, &USART_InitStructure);
	/* Enable receive interrupt */
	USART_RDR_INT_Enable(USARTx, TRUE);
	/* Enable LIN moudle */
	USART_RESHD_Enable(USARTx, TRUE);
	/* Enable LIN break interrupt */
	USART_Blank_INT_Enable(USARTx, TRUE);
	USART_Cmd(USARTx, TRUE);

	USART_DMA_Read_Receive_Enable(USARTx, TRUE);
	USART_DMA_Write_Transmit_Enable(USARTx, TRUE);
}

配置发送DMA配置

#define LIN_DATA_LEN_8_BYTE (1 + 1 + 8 + 1) /*SynchField+PID+Data+CheckSum*/

void Usart_Dma_Init(USART_SFRmap *USARTx)
{
	/* Reset the DMA0 peripheral to enable the peripheral clock */
	DMA_Reset(DMA0_SFR);
	/*
	 * DMA0_TX configured as follow:
	 *   - DMA channel selection channel 1
	 *   - Bit width of memory = 8
	 *   - Cyclic mode disable
	 */
	DMA_InitTypeDef DMA_TX_INIT, DMA_RX_INIT;
	DMA_TX_INIT.m_Channel = DMA_CHANNEL_2;
	DMA_TX_INIT.m_Direction = DMA_MEMORY_TO_PERIPHERAL;
	DMA_TX_INIT.m_PeripheralDataSize = DMA_DATA_WIDTH_8_BITS;
	DMA_TX_INIT.m_MemoryDataSize = DMA_DATA_WIDTH_8_BITS;
	DMA_TX_INIT.m_Priority = DMA_CHANNEL_LOWER;
	DMA_TX_INIT.m_Number = LIN_DATA_LEN_8_BYTE;
	DMA_TX_INIT.m_PeripheralInc = FALSE;
	DMA_TX_INIT.m_MemoryInc = TRUE;
	DMA_TX_INIT.m_LoopMode = FALSE;
	DMA_TX_INIT.m_BlockMode = DMA_TRANSFER_BYTE;
	DMA_TX_INIT.m_MemoryAddr = (uint32_t)0;
	DMA_TX_INIT.m_PeriphAddr = (uint32_t) & (USARTx->TBUFR);
	DMA_Configuration(DMA0_SFR, &DMA_TX_INIT);
	/*
	 * DMA0_RX configured as follow:
	 *   - DMA channel selection channel 2
	 *   - Bit width of memory = 8
	 *   - Number of data transmitted = 100
	 *   - Cyclic mode disable
	 */
	DMA_RX_INIT.m_Channel = DMA_CHANNEL_3;
	DMA_RX_INIT.m_Direction = DMA_PERIPHERAL_TO_MEMORY;
	DMA_RX_INIT.m_PeripheralDataSize = DMA_DATA_WIDTH_8_BITS;
	DMA_RX_INIT.m_MemoryDataSize = DMA_DATA_WIDTH_8_BITS;
	DMA_RX_INIT.m_Priority = DMA_CHANNEL_LOWER;
	DMA_RX_INIT.m_Number = LIN_DATA_LEN_8_BYTE + 1;
	DMA_RX_INIT.m_PeripheralInc = FALSE;
	DMA_RX_INIT.m_MemoryInc = TRUE;
	DMA_RX_INIT.m_LoopMode = TRUE;
	DMA_RX_INIT.m_BlockMode = DMA_TRANSFER_BYTE;
	DMA_RX_INIT.m_PeriphAddr = (uint32_t) & (USARTx->RBUFR);
	DMA_RX_INIT.m_MemoryAddr = (uint32_t)LinRxFrame.Data;
	DMA_Configuration(DMA0_SFR, &DMA_RX_INIT);
}

中断处理:

void __attribute__((interrupt)) _USART5_exception(void)
{
	volatile uint8_t Rev_Temp;
	if (USART_Get_Blank_Flag(USART5_SFR))
	{
		/* 清除间隔场中断标志位 */
		USART_Clear_Blank_INT_Flag(USART5_SFR);
		
		/* 重置接收状态 */
		//user cod 
	}
	if (USART_Get_Receive_BUFR_Ready_Flag(USART5_SFR))
	{
		/* 清除接收中断标志位 */
		USART_Clear_Receive_BUFR_INT_Flag(USART5_SFR);
		/* 读取数据 */
		val = USART_ReceiveData(USART5_SFR);
	
	    //user  cod 
	}
}

这样配置ok后,在中断判断完间隔场中断后,进行ID判断,如果ID是从机所需id,那么即可进行相应的发送或者接收操作,此过程和串口接收完全类似,不同的是,需要注意检验场的发送不要遗漏。

好啦,lin的配置就这些啦,本次更新时间为20230313。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值