335_通过CAN通信实现printf

64 篇文章 165 订阅
36 篇文章 18 订阅

完整的S32K144的学习汇总如下:

https://github.com/GreyZhang/g_s32k144

    以前的学习笔记写起来,都有一种整理测试记录或者调试记录的感觉。我觉得其实这样虽然简明扼要,但是总是少了一种生活的味道。或许,以后把我的学习笔记写得更加生活化一点会更有意思。至于学习中的几个要点,只要是笔记的内容够短总能快速提取出来。

    今天的学习笔记说起来有一点点故事性,这得从我对printf的好感建立说起。工作了大概三四年后,我依然么有对printf有什么好感。或许,这个跟我从事的行业有关。我做的汽车电子嵌入式,更多时候是依赖调试器。我对于printf的好感其实还是来自于我业余的自我能力提升,尤其是当我在一篇文章中看到了ken老爷子的软件调试方式之后。Ken老爷子不喜欢周期超过一个月的项目,在进行软件设计的时候先把接口全都写完,软件还完成就直接先启动联调测试。而整个开发调试过程中,ken老爷子需要的只是一个文本编辑器和printf。突然间,我似乎灵光一点,瞬间有所顿悟。其实,只要有一个方便的监控方式,很多调试其实都很容易。自此,我喜欢上了printf。

    然而,回到我自己从事的行业,这个实现却有一点点费劲了。在汽车电子领域,主控单元中基本上没有串口,而我们见到的大多数的printf要么通过串口要么通过调试器所谓的半主机模式。这个,在我接触的项目中都绝少存在。相比之下,我们用的更多的是调试器以及CAN,基于CAN会派生出大量的监控手段。一定程度上来说,我们的问题得到了解决。但是,CAN派生出来的大量的软硬件工具都价值不菲,尤其不适合个人学习使用。即便是公司,很多时候也没有实力大批量采购。这时候,其实还有一个简单的方案:基于CAN做一个printf打印工具。如果有了这么一个想法,实现起来还是很容易的。尤其是如果我们基于CAN卡做过上位机开发的时候,我们只需要定义简单的规则,实现一个上位机的解析即可。不过,对于大多数的嵌入式工程师来说,学习成本略高。

    那么,还有没有其他的解决方案呢?其实,解决方案还是有的,哪怕是一种纯粹的嵌入式的解决方案。既然,通过串口能够轻松实现printf,那么,我们实现一个CAN到串口的转换,一切不就很简单了吗?这个功能,其实我已经在Arduino的平台上实现了,通过Arduino + MCP2515就可以轻松实现。相比之下,S32K144是否可以做到呢?当然可以,而且有更大的优势。因为,CAN以及串口在这个板子上都是已经集成好了的,我们不需要额外扩展硬件模块。至于printf的实现,方式很多种,我自己采用的方式是放弃标准库接口修改,采用一个独立的代码实现。有很多开源的代码可以参考,我们只需要实现一个简单的putc函数就可以完成整个功能。

    由于串口以及CAN的速度,我们的printf函数实现有时候会觉得性能稍弱,尤其是粗暴的实现不做任何优化的情况下。其实,我自己到觉得这完全不是问题,printf的目的不是为了性能而存在的更多时候我们需要的是满足我们眼睛观察的需要。其实,我个人觉得每秒能够按顺序输出100个字节的速度完全足够我们调试90%以上的软件。

    这样,我们就可以在ECU中,putc完全定制为一个CAN的字节发送就完成了ECU的printf功能。S32K144 EVB的作用在哪里呢?它的作用自然是提供CAN printf打印内容的一个解析。大致的数据流如下:

    ECU à CAN printf à CAN bus à S32K144 CAN receive à S32K144 UART transmit à 电脑显示。

    看上去费劲,但是一次定制之后这个就可以固化为一个常用的工具存在。我做一个简单的实现如下:

    当接收到的CAN报文ID是我的ECU printf CAN ID,那么,我把数据场的信息打印出来。接下来,我使用上位机做一个ECU打印的模拟。

    打印的输入内容是ASCII码的字符,因此,我的串口应该可以打印出一个预期的字符串。

    调试的时候,成功打印出来了“helloCAN”的字符串。机制的测试基本成功,在实际的使用中,尤其是ECU还是有一定的细节处理。这部分实现其实相对容易,在这里就不做介绍了。

    “世界上并不缺少美,只是缺少发现美的眼睛”。世界上也没有调试不了的BUG,大多数时候是我们没有看到足够多的信息。我希望这个简单的printf能够为看到我学习自己的你,提供一双更加犀利的眼睛!

完整的S32K144的学习汇总如下:

https://github.com/GreyZhang/g_s32k144

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
下面是一个基于GD32F205芯片的CAN通信程序示例: ```c #include "gd32f20x.h" #include "gd32f20x_can.h" /* CAN初始化函数 */ void CAN_Configuration(void) { CAN_InitPara CAN_InitStructure; CAN_FilterInitPara CAN_FilterInitStructure; /* 使能CAN时钟 */ RCC_APB1PeriphClock_Enable(RCC_APB1PERIPH_CAN0,ENABLE); /* CAN单元复位 */ CAN_DeInit(CAN0); /* CAN单元初始化 */ CAN_InitStructure.CAN_TTCM = DISABLE; CAN_InitStructure.CAN_ABOM = DISABLE; CAN_InitStructure.CAN_AWUM = DISABLE; CAN_InitStructure.CAN_NART = DISABLE; CAN_InitStructure.CAN_RFLM = DISABLE; CAN_InitStructure.CAN_TXFP = DISABLE; CAN_InitStructure.CAN_Mode = CAN_MODE_NORMAL; CAN_InitStructure.CAN_SJW = CAN_SJW_1TQ; CAN_InitStructure.CAN_BS1 = CAN_BS1_11TQ; CAN_InitStructure.CAN_BS2 = CAN_BS2_4TQ; CAN_InitStructure.CAN_Prescaler = 2; CAN_Init(CAN0,&CAN_InitStructure); /* CAN过滤器初始化 */ CAN_FilterInitStructure.CAN_FilterNumber = 0; CAN_FilterInitStructure.CAN_FilterMode = CAN_FILTERMODE_IDMASK; CAN_FilterInitStructure.CAN_FilterScale = CAN_FILTERSCALE_32BIT; CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000; CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000; CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0; CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; CAN_FilterInit(&CAN_FilterInitStructure); } /* CAN发送函数 */ void CAN_SendData(uint32_t StdId,uint8_t* data,uint8_t len) { uint8_t i; CAN_TransmitPara CAN_TxMessage; CAN_TxMessage.CAN_IDE = CAN_ID_STD; CAN_TxMessage.CAN_RTR = CAN_RTR_DATA; CAN_TxMessage.CAN_DLC = len; CAN_TxMessage.CAN_STDID = StdId; for(i=0;i<len;i++) { CAN_TxMessage.CAN_Data[i] = data[i]; } CAN_Transmit(CAN0,&CAN_TxMessage); } /* CAN接收函数 */ void CAN_ReceiveData(void) { uint8_t i; CAN_ReceivePara CAN_RxMessage; if(CAN_MessagePending(CAN0,CAN_FIFO0)==SUCCESS) { CAN_Receive(CAN0,CAN_FIFO0,&CAN_RxMessage); for(i=0;i<CAN_RxMessage.CAN_DLC;i++) { printf("%c",CAN_RxMessage.CAN_Data[i]); } printf("\r\n"); } } ``` 在主函数中可以这样调用: ```c int main(void) { uint8_t data[8] = {'H','e','l','l','o',' ','C','A'}; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); CAN_Configuration(); while(1) { CAN_SendData(0x123,data,8); CAN_ReceiveData(); } } ``` 注意,这里的例子只是一个简单的示例,实际应用中还需要进行相应的修改。另外,还需要在GPIO配置中将CAN引脚设置为CAN功能,具体可以参考GD32F20x系列的数据手册。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值