完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
在想一个问题。。。为什么树可以长这么高?狗可以单身这么久?
我不明白。。。 先将代码更改前的注释贴出来 /****************************************************************** Lin总线帧格式:帧头+应答 帧头:同步间隔段(至少13个显性电平)+同步间隔段间隔符(至少1位隐形电平)+同步段(0x55)+字节间间隔+PID(ID+校验位) 注:PID=ID(6位)+校验(2位) ID 取值范围为: 0x00~0x3f ID的取值分类: 信号携带帧 : 0x00~0x3b 诊断帧(主机请求):0x3c 诊断帧(从机应答):0x3d 保留帧 : 0x3e,0x3f P0 = ID0⊕ID1⊕ID2⊕ID4 异或运算 P1 = ┐(ID3⊕ID4⊕ID5⊕ID1) 异或后取非 应答:应答间隔+数据段+校验和段 注:数据段 低字节的低位先发 标准型校验和:只校验数据段 增强型校验和:校验数据段以及PID 诊断帧只能用标准型校验和 ******************************************************************/ /****************************************************************** lin中断接收函数功能: 1、回环效果:即主机发送帧头或者主机发送帧头+应答,主机的中断服务程序都会接收数据。 可以检测出:主机串口Tx、Rx、Lin脚,三个引脚上的信号是相同的(除了电平不同)。 2、当串口检测到连续至少11位显性电平即进入中断开始接收。 3、中断服务函数接收数据时按进程推进 ①接收同步段是否OK? ②接收ID校验后解析是数据执行还是反馈 若是执行: 若是反馈: ③分步接收数据 ③准备数据在帧头结束后发送数据 ④匹配校验数据是否正确 ⑤解析数据并执行 ******************************************************************/ STM32作为主机部分代码: // 主机帧头部分 void Lin_SendBreak(void) { USART_SendBreak(USART1); } 起先是同步间隔段,因为作为主机要连续发送至少13位显性电平,这里用的是STM32自带的库函数,直接调用就行。 oid Lin_SendSyncSegment(void) { USART_SendData(USART1,0x55); while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET ); } 接着就是同步段,发送0x55 u8 Lin_CheckPID(u8 id) { u8 returnpid ; u8 P0 ; u8 P1 ; P0 = (((id)^(id>>1)^(id>>2)^(id>>4))&0x01)<<6 ; P1 = ((~((id>>1)^(id>>3)^(id>>4)^(id>>5)))&0x01)<<7 ; returnpid = id|P0|P1 ; return returnpid ; } 然后就是发送PID(protect ID),这里的前六位为ID,后两位为校验位,函数功能为:输入ID,返回PID。 void Lin_SendHead(u8 id) { Lin_SendBreak(); Lin_SendSyncSegment(); USART_SendData(USART1,Lin_CheckPID(id)); while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET ); } 该函数体就是单片机作为主机发送的帧头,可以指定ID发送帧头,接收从机返回的数据;也可以发送帧头+数据,让从机接收。 // 是经典校验还是增强校验,另:诊断帧只能经典校验 u8 Lin_Checksum(u8 id , u8 data[]) { u8 t ; u16 sum ; sum = data[0]; if(id == 0x3c) // 如果是诊断帧,用经典校验 { for(t=1;t<8;t++) { sum += data[t]; if(sum&0xff00) { sum&=0x00ff; sum+=1; } } sum = ~sum; return (u8)sum ; } for(t=1;t<8;t++) { sum += data[t]; if(sum&0xff00) { sum&=0x00ff; sum+=1; } } sum+=Lin_CheckPID(id); if(sum&0xff00) { sum&=0x00ff; sum+=1; } sum = ~sum; return (u8)sum ; } 此段函数功能:输入ID+数据,返回校验和段,里面有调用返回PID函数。诊断帧只能用标准校验这里还没有验证过,因为校验还没有测试。 void Lin_SentData(u8 data[]) { u8 t ; for(t=0;t<8;t++) { USART_SendData(USART1,data[t]); while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET ); } } 数据发送函数,仅仅是调用STM32的库函数进行for循环发送。 上面三个函数是单片机无论作为主机还是从机都需要用到的部分,所以在后面进行预编译选择的时候,放到外面。 void Lin_SendAnswer(u8 id ,u8 data[]) { Lin_SentData(data); USART_SendData(USART1,Lin_Checksum(id,data)); while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET ); } 这里是主机的响应函数调用。 STM32作为从机部分代码: 由于从机部分不需要发送帧头,所以相对来说,任务轻松不少。 除却上面三个共用的函数体外。仅有一个函数体来对接收到的报文进行解析执行。然后就是在中断函数体内,当接收到需要本从机反馈数据时,进行数据反馈。 void Lin_DataProcess(void) { u8 ReceiveID ; u8 PIDChecksum ; u8 SumCheck ; if(DataReceiveflag == 1) { ReceiveID = ReceivePID&0x3f ; PIDChecksum = Lin_CheckPID(ReceiveID); if (PIDChecksum != ReceivePID) { return ; } else {} if(FrameReceiveOverFlag == 1) // 从机需要执行信号 { SumCheck = Lin_Checksum(ReceiveID,LinReceiveData); if(ReceiveCheckSum != SumCheck) { return ; } else {} if(ReceiveID == 0x23) { if(LinReceiveData[3] == 0x01) { LED0 = 0 ; } else if(LinReceiveData[3] == 0x02) { LED0 = 1 ; } else {} } } FrameReceiveOverFlag = 0 ; DataReceiveflag = 0 ; } } 当接收到ID为0x23的报文时,进行LED灯的点亮功能。 void USART1_IRQHandler(void) //串口1中断服务程序 { u8 ReceiveData; u8 ReceiveID; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断 { ReceiveData =USART_ReceiveData(USART1); //读取接收到的数据 if(DataProcess == 0) { if(ReceiveData != 0x55) { return ; } if(ReceiveData == 0x55) { DataProcess = 1 ; return ; } } if(DataProcess == 1) { ReceivePID = ReceiveData ; ReceiveID = ReceivePID&0x3f ; if(ReceiveID == 0x33) // 从机需要反馈信号 { Lin_SentData(testdata); USART_SendData(USART1,Lin_Checksum(ReceiveID,testdata)); while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET ); DataProcess = 0 ; return ; } DataReceiveflag = 1 ; DataProcess = 2 ; return ; } if(DataProcess == 2) { if(DtRProcess<8) { LinReceiveData[DtRProcess] = ReceiveData ; DtRProcess += 1 ; if(DtRProcess == 8) { DtRProcess = 0 ; DataProcess = 3 ; return ; } } } if(DataProcess == 3) { ReceiveCheckSum = ReceiveData ; FrameReceiveOverFlag = 1 ; DataProcess = 0 ; } } } 标注下今天出现的问题: ①调用串口发送函数时,忘记检测发送完成标志,因为数据发送比较快,导致数据严重丢失。 ②当单片机作为从机进行数据反馈时,反馈数据发送是在主机发送帧头之后紧接着的。起初是设置一个标志位,在中断外面进行数据发送的,这就导致帧头与应答部分时间间隔不明确,极大可能会超过响应间隔的时间。所以后期是在中断里面发送应答部分。当检测到ID为需要应答时,在中断里应答,后面数据不再接收。 2020.05.23增加: ③当单片机作为从机需要反馈数据时(主机发送帧头,从机需补充数据时),响应不在中断里面做。中断里设置标志位,在中断外填充数据,每1ms检测一次。在用RTOS时,将优先级设置最高?(只要响应与帧头的间隔时间在Lin的规定最长时间内就行)。。另外,由于环回效果(即自身发送的同时也会进入中断接收自身发送到总线的数据)可能会将从机的反馈与帧头的时间加大,可逐步屏蔽进入中断条件,待需要接收时再重新开启。 工程包我会上传到资料以做备份使用。 测试截图: 单片机作为主机进行主机帧头+主机应答 单片机作为主机进行主机帧头+从机(上位机)应答 主机(上位机)帧头+主机(上位机)数据控制单片机灯亮灭(单片机读取并解析数据执行) 主机(上位机)帧头+从机(单片机)应答 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
878 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
670 浏览 1 评论
415 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
327 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
736 浏览 2 评论
1472浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
144浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
186浏览 3评论
166浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
168浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-6-29 05:16 , Processed in 0.874040 second(s), Total 78, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191