作者:心机之花
链接:https://www.zhihu.com/question/26776219/answer/244433861
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

说下我的学习过程。刚到公司的时候我根本不知道什么是CAN,甚至连以太网和串口通讯都不懂。领导把USBCAN分析仪拿给我,把铜线短接上,用软件在CAN1窗口点下发送,CAN2窗口马上接收到了发送出来的数据,ok,成功了。这就是CAN通讯。所以第一点,你想学汽车CAN总线,你首先要有个USBCAN分析仪。否则你无法看到CAN总线的原始数据。示波器?需要购买有CAN总线数据分析功能的示波器。

1.一个USBCAN分析仪(买或者自己做)

分析仪这东西我看知乎上还是土豪居多。USBCAN分析仪属于舶来品,原产于欧洲,我们国内用的较多的有VN1630A(Vector出品,用CANoe软件),PCAN-USB(PEAK公司出品,国内用量大),Kvaser的USBCAN(瑞典知名公司),USB2CAN(IXXAT公司,德国),NI自己的USBCAN。其特点是昂贵但功能强大,Peak最便宜的无隔离版本也要2000多块,Vector的硬件价格更是极高。作为学生党买不起,何谈学习?接下来说下国产货,ZLG作为知名的嵌入式龙头企业有很多CAN设备卖,但同样的,价格上也是1200-2200人民币不等,小贵。最后是平民价位的CAN分析仪,淘宝和京东都有,200-600元不等,这个价位大家还是可以接受的。在这里不推荐大家购买250元以下的分析仪。很便宜的分析仪大多是USB转串口,再转CAN,这样的分析仪接收高负载数据时会出现丢帧的现象,之后我们也会说下如何自制一台这样的USB转串口转CAN分析仪。别图便宜,看下淘宝销量排行,不要省那100元钱,用不好还要退货,麻烦。总结下,初学CAN,如果有足量科研经费,应该优先采购欧洲设备,毕竟软件功能多,性能好;如囊中羞涩,先买平价国产分析仪接收数据完全可以满足需要。附:USBCAN的百度词条

USB-CAN_百度百科

2.基础知识扫盲

第一点完毕。第二点是足额的CAN技术扫盲,来源是书和度娘。入门书籍的选择很重要。在这里推荐的是《项目驱动:CAN-bus现场总线基础教程 周立功 新华书店正版畅销图书》。这书实在便宜还好用。推荐大家花时间把前两章反复看几遍。

高速CAN的电平信号(有差分电压表示0,没有则表示1)CAN总线标准数据帧的结构(无需过多了解)

你说我不喜欢看书,直接上资料?有的。清华PPT和大众PPT是典范,链接在下面。

清华大学教程――CAN总线原理及应用_图文_百度文库

【图文】上海大众帕萨特CAN数据总线的结构原理_百度文库

一汽大众CAN-BUS培训资料_图文_百度文库

你说我是搞ARM的,最近公司让我用STM32开发CAN接口设备,下面是初级入门用的材料。

链接:https://pan.baidu.com/s/1goTfK1QjNVirbdtqQLFs4w 密码:84sd

链接:https://pan.baidu.com/s/1rs2zmZZYs2LFYgro7bmd-A 密码:zdgq

这个是野火和正点原子两家的开发手册,翻到CAN总线那部分,推荐直接使用ST的库函数,先实现功能,有余力再看寄存器,免得走弯路。这手册里面的CAN总线更侧重于开发和使用,基础的东西讲得少。

3.找个CAN设备测量数据

第三点是实际操作,在实际测试中巩固理论知识。

CAN总线不是空中楼阁。不管你测什么东西的CAN信号都行,重要的是,你要接收到那些宝贵的CAN总线数据。举个例子,你的汽车,你们项目组租的车,你导师的车都行。反正我能想到的最方便的资源就是你身边的车,只要是09年之后的车都带CAN总线。我当时是测我自己的速腾车,但OBD接口的CAN被阉割了,没有数据。后来从汽车之家论坛中发现空调CAN线能引出来,这样才引出了两条宝贵的100K波特率舒适CAN总线,测出了很多数据。

汽车的CAN分为动力CAN和舒适CAN,具体可以看PPT。我测的速腾舒适CAN内容很丰富,车门、尾箱打开还是关闭,安全带,档位,油量,手刹,方向盘转角等等一应俱全,但都是CAN总线源码,你不知道哪个信号是车门信号。这个就叫做逆向破解了。你需要频繁的开关车门来确定车门信号所对应的帧ID和帧数据。你动,它跟着动,你不动,它也不动,那就是它了。

什么是帧ID?在实际应用中,CAN总线一个帧主要由帧信息帧ID帧数据组成。CAN总线又分为3种,高速CAN、容错CAN、单线CAN。妈呀,啥是高速CAN?高速CAN有别于容错CAN和单线CAN,高速CAN的电平静默2.5V,上下限是3.5V和1.5V,容错CAN显性时则为1V和4V,故可用万用表量出。容错CAN和单线CAN的市场占有率小,可暂时不学。附录:高速CAN、容错CAN、单线CAN区别
高速CAN,低速CAN, 单线CAN 比较

帧信息:四类,标准数据帧(汽油车、电机)、标准远程帧(少见)、扩展数据帧(广大柴油车、部分汽油车)、扩展远程帧(少见)

有童鞋经常会问到CAN2.0A和CAN2.0B是啥,2.0A是标准的意思,帧ID11位,也即0x000-0x7FF。2.0B是扩展的意思,帧ID最高29位,也即0x0000 0000-0x1FFF FFFF,要注意2.0B已经包含了2.0A,他们俩是包含与被包含的关系。

帧ID是什么?通俗讲是CAN的一种“地址”。CAN有个特点是竞争机制帧ID越小越有占用总线资源的权利,越会优先发送。举个例子,灯光信号帧ID0x555,发动机温度传感器帧ID0x111,那么当两个信号同时发出时,发动机的信号会优先发送,灯光在后面排队。通常在一个CAN系统中,不同的设备,发出CAN信号的帧ID都是不一样的,或者说,CAN信号的每个帧ID都有一个固定的用途。如果CAN信号的帧ID的用途被确定下来,并在一个文档中得到了解释,那么我们管这个叫CAN总线的应用层协议,或者高层协议。常见的有ISO15765-4,SAE J1939,CANopen(电机和挖沟机控制器用)。而这个文档在车辆行业中叫DBC文件,它对车辆CAN总线上的每个帧ID及每个帧数据都做了注释。

11位和29位是什么意思呢?现在说下,11位指的是标准帧的帧ID范围是0x000-0x7FF(0x是十六进制的意思),7FF翻译成二进制是111 1111 1111,对吧,十一个“1”。同理,29位指扩展帧的帧ID范围是0x0000 0000-0x1FFF FFFF,1FFF FFFF翻译成二进制是29个1。大致明白了吧。29位的分配ID能力比11位的强,11位总有些地方不够之感。

帧数据很简单了,说下特色吧。与串口相比,CAN的帧数据只有8个字节,即64个位,不会再多了。当然,CAN FD作为新型总线解决了仅有8字节这个问题。有兴趣大家可以了解下CAN FD。

波特率忘了,CAN的波特率都是整数,要注意。常见的车辆波特率有500K,250K,125K,100K。波特率这东西和收音机频率一样,如果两个CAN设备的通信波特率不一致的话,是不能进行通讯的。

常见CAN高层协议及其波特率

终端电阻,CAN和RS485一样,要在终端减少差分信号的反射。我记得最经典的一张图是这么画的,水流在试管(平躺)的尾部受阻,水也就涌了回来。差分信号也是如此,你不在两个终端加电阻,信号会反弹回来影响通讯。详细的看书吧,不细讲了。这东西总线上要有两个,两个120欧姆的电阻,并联,最远的两端一边一个。多了不行少了也不行。你不确定的话,用万用表量一下,CANH和CANL之间60欧姆左右最好。

CAN总线的终端电阻

好的,现在你应该已经明白,帧ID帧信息帧数据都是什么,知道CAN总线波特率是什么,终端电阻是什么,重要的是,你收到一个陌生设备发出的CAN总线数据了。你成功的迈出了学习CAN总线最重要的一步。如果你连接不上你的车或其他CAN设备,那属于连接问题,请参阅指导文档
https://jingyan.baidu.com/article/3a2f7c2e213d1d26afd61197.htm

4.理解CAN高层协议

第四点,你需要找一个高层协议来进行CAN数据与实际含义对号入座。比如ISO15765-4协议和SAE J1939协议,看文档,明白CAN总线是如何在某个帧ID中传递转速等模拟量,传递灯光信号等数字量。

举个例子,J1939柴油车协议中,0x18F00402这个帧ID表示EEC1,它的第四个和第五个帧数据,假如是0x02,0x03,那么发动机转速如何表示呢,转速=2x0.125+3x32=96.25,这个就是真实的发动机转速值。它是有公式在里面的,这个事情是在协议中规定好的。用第四个帧的十进制数据乘以0.125,再加上第五个帧的十进制数据乘以32,你就得到了实际的发动机转速。对CAN总线协议的理解就说到这里。知道帧ID和帧数据的意思,你就可以对复杂的CAN总线16进制数据了如指掌。

SAE J1939协议截图大众某车型的CAN数据含义

我们再看一个例子,上图是大众某畅销车的数据解析结果,帧ID为0x390的标准数据帧,第三个帧数据如果为0x40说明左前车门关闭,如果为0x41说明左前车门打开。这个有什么意义呢?如果我们做一款中控车机,我们知道有一个功能叫车辆状态读取,如果车门未关但车辆已开始行驶,车机需要知道左前门目前的状态,通过什么呢?就是CAN总线。车机会读取CAN总线的信息,得知车体的门信息、安全带信息、手刹信息等,通过语音模块给予驾驶员必要的提醒。话说我有时真的会忘记放手刹,真的很感谢德赛西威的车机及时提醒我。

很多上了年纪的工程师,经常甩给我一个某某车厂零部件的通信协议,说:”我发什么数据给它,它才能动作啊?车厂的人只给了我这个通信协议,我也看不懂。”其实通信协议上面写明了帧ID和帧数据意思,按图索骥,你就可以发一条CAN数据,启动汽车的某个部件,很神奇。

5.做些关于CAN总线的项目(硬件接口或上位机)

第五点,做些实际的项目吧,可以帮助身边的亲们做些CAN总线有关的外延工作。比如我做的是CAN总线的接收设备。因为公司有一些新品测试工作,这些工作绝大多数都需要检测CAN口的好坏,所以我用stm32设计了一个简易的反弹信号电路,如果测试不通过会亮红灯。被嘉立创收了很多贴片的钱以后,实体电路板上线了,同事用的很开心。在这里强烈推荐硬件基础弱的同学直接用立创EDA,这个EDA软件的封装啊、部分原理图都是共享的,选件的时候还可以考虑贴片的问题,很多小电阻、小电容什么的可以直接贴在你设计好的电路板上,极大程度上节省你的时间。我除了接插件和主芯片不用它家贴,其他都是直接让嘉立创贴好再给我邮过来。

学CAN总线还是需要用项目来背书的,如果你软件方面牛,可以用第三方的CAN分析仪当硬件,自己开发上位机软件,开发一些有特殊功能的软件,我国目前缺少诊断、数据分析、协议分析等方面的软件,尤其是汽车方面,绝大多数为英文的,需要从国外购买。我能想到的有电动车充电管理系统,车辆信息读取软件,CAN Bootloader软件等。我日常接触的比较常见的软件有BMS电池管理系统、消防信号管理系统、伺服电机管理系统什么的。CAN不算是新鲜货,主要的应用领域集中在汽车、BMS、电机控制等几个方向内。

如果你硬件方面不错,可以尝试下汽车类CAN总线设备的开发,ARM9,Cortex M3,DSP都可以的,懂些CAN总线终归是好的。这方面有市场,朗仁做汽车诊断仪,格尼希尔做远程启动,腾讯前些年有腾讯路宝,还有铁将军,BMS相关企业,甚至是无人驾驶,都离不开CAN总线的相关开发。

 

想要学习汽车CAN总线,首先要了解汽车CAN总线概述、汽车误撞诊断协议的发展、基于UDS的ISO15765协议等这些关于CAN总线的前世今生。

汽车诊断协议的发展

当今车辆的电控系统越来越多,比如发动机系统ABS、SRS、电动车窗、悬挂、电动箱子等等。与此同时,监控已经遍布于车身的各种传感器,我们能够获取实时状态信息,并将这些信息发送到相应的控制单元当中。每个控制单元同时可以接受各种各样的信息,并对各种信息进行处理、分析,随后发出相关的指令。比如发动机系统可以接受来自进气压力传感器、发动机温度传感器、油门踏板位置传感器、发动机转速传感器等信息,经过分析和处理之后会发送相应的指令来控制喷油嘴的喷油量,比如说喷油时间、喷油脉宽及点火提前角等。

其他的控制单元工作原理同发动机系统类似,车身上的这些控制单元并不是独立工作,而是作为汽车这样一个整体,它需要信息的共享,因此存在一个信息传递的过程。CAN总线就是把以前一线一用的专线制改成一线多用制,这样可以大大减少汽车上电线的数量,也可以简化整个汽车的布线。在形成OBD-II标准之前,各厂商的汽车诊断座均不相同。比如奔驰为38帧,美洲车12帧,欧宝为10帧,丰田为17帧,宝马为20帧,本田为3帧,澳大利亚西亚款6脚等。

各种各样的诊断插头

各种类型的诊断协议

由于各厂商汽车诊断座与诊断协议差别巨大,导致汽车发生故障时其类型难以判定。因此,SAE(美国机动车工程师学会)制定了OBD-II标准,实行标准检测程序,并且具有严格的排放针对性,用于实时监测汽车尾气排放情况。

OBD-II标准诊断座

在CAN总线形成标准协议前,欧洲和大部分亚洲汽车采用ISO9141协议,美国通用汽车(GM)使用SAE J1850 VPW通讯协议电路,福特(FORD)汽车则采用SAE J1850 PWM通讯协议电路。可以看出此前以KWP2000协议居多,KWP2000协议最初是基于K线的诊断协议,但由于K线的物理层和数据链路层在网络管理和通讯数据上的局限性,K线逐渐无法满足日益复杂的车载诊断网络的需求。而CAN总线由于其非破坏性的网络仲裁机制、较高的通讯数据和灵活可靠的通讯方式,在车载网络广受青睐,绝大多数车场目前都是采用CAN总线的方式。所以基于K线的KWP2000物理层和数据链路层的协议逐步被基于CAN线的KWP2000协议,也就是ISO15765协议所取代。

K线与CAN总线的比较

K线通信速率较慢,最大达10.4 Kbit/s。此前有一款老款的宝马车是115200bit/s的波特率,但是这种非常罕见。CAN线通信速率可达到1 Mbit/s,其中以500 Kbit/s和250 Kbit/s为主。在传输方面,K线采用单线传输的方式,以字节为单位进行传输,CAN线则以差分信号传输的方式,以CAN帧为单位进行传输。在出错处理中,K线必须要由开发者,如tester,ECU等来完成相应的仲裁处理。而CAN线在物理层面具有完善的通信错误处理机制和总线仲裁机制。报文长度方面,K线最大255个字节,CAN线则是4096字节(指数据域)。

物理层基于K线

对于OSI分层中的应用层,它的增强型的诊断是基于ISO 14230-3协议,此外还有一些由厂商自行进行定义。而与排放相关的诊断是基于ISO 15031-5协议。

ISO14230协议

KWP2000协议的数据结构由帧头、数据字节和校验和三部分组成。帧头包括起始字节、原码、目的地址和帧长。数据字节包括SourceID与有效字节,共255个字节,最后是累加校验和。这三部分就组成了一帧的数据进行通讯。

KWP2000协议由于是以字节为单位,所以会涉及到时间。从下图中可以看出它共有四个时间:Tester的字节时间,ECU 1与ECU 2的字节时间,以及ECU收到Tester之后的帧间隔时间。

一般情况下,P4Tester的字节时间一般默认是20ms左右。P2表示ECU间隔Tester的时间,一般默认是50ms。ECU的P1字节时间默认也是20ms。假设Tester发送8个字节数据,ECU也回复8个字节,P2的间隔时间是50ms,那么获得一帧数据需要320ms的时间,这样获取汽车ECU的数据时间就比较长,效率比较低下。

物理层基于CAN线

基于CAN线的OSI分层结构,其增强型的诊断是基于ISO 14229-1协议与ISO 15765-3协议。而它的排放标准与K线相同,都是基于ISO 15031-5协议。

ISO 15765协议

汽车CAN总线概述

简介

CAN总线最初并不是用于功能开发,而是一种串行的通讯方式,它有着很高的安全等级。特性:

  1. 报文可区分优先级,通过ID号进行区分;
  2. 保证延迟时间;
  3. 设置非常灵活;
  4. 时间同步的多点接收;
  5. 系统内数据的连贯性;
  6. 多主机(任何一个节点都可以当主机);
  7. 错误检测和错误标定;
  8. 只要总线一处于空闲,它就将自动破坏的报文重新进行传输。
  9. 可以将节点的暂时性错误和永久性错误区分开来。

差分信号采用双角线CAN H和CAN L

汽车CAN总线网络拓扑结构

从下图总线中可以看到,在总线中一般挂有很多的ECU,相关的ECU就近采集相关传感器的数据,通过总线来进行传输,这样就可以大幅减少汽车整车的布线。

报文传输

报文的传输中帧格式分为11位识别符的标准帧与29位识别符的扩展帧。帧类型则分为数据帧、远程帧、错误帧和过载帧,这里主要讨论数据帧。

报文滤波的作用是通过设置硬件的滤波器从而过滤不需要被接受的CAN报文。汽车上的节点非常多,但对于每个节点来讲并不是需要所有的数据。比如在ABS系统并不需要掌握发动机的参数信息,此时就可以通过设置滤波器而过滤掉这些数据,起到滤波器的作用。

数据帧由七个不同的位场组成:帧起始(Start of Frame)、仲裁场(Arbitration Frame)、控制场(Control Frame)、数据场(Data Frame)、CRC场(CRC Frame)、应答场(ACK Frame)、帧结尾(End of Frame)。仲裁帧可以用来区分该帧是11位的标准帧还是29位的扩展帧,以及是数据帧还是远程帧。

基于UDS的CAN总线ISO 15765协议

Network layer protocol data units

网络层的ISO15765协议最多可以发送或接收4096个字节。

从上图中可以看到PDU有四组数据类型,分别是单帧的SF N_PDU,首帧的FF N_PDU,连续帧的CF N_PDU和流体控制帧的FC N_PDU。

单帧第一个字节的高四位是0,低四位表示帧长,即这一帧有几个字节的有效数据。

首帧第一个字节的高四位是1,第一个字节低四位与第二个字节一同组成帧长,所以最大的是4095个字节。

连续帧第一个字节的高四位是2,SN表示计数器。

流体控制帧第一个字节的高四位是3,低四位是FS(FlowStatus),当FS为0的时候表示继续发送,1表示等待,2则表示溢出。BS为0表示ECU或Tester可以持续回复连续帧数据,BS值非0表示回复连续帧的帧间隔之间可以插入一帧流体控制帧。STmin可以控制连续帧的帧间隔时间,当一些控制器速度达不到要求时,可以通过控制连续帧的帧间隔时间,使其存储到缓冲器中,进行处理。

CAN的UDS

基于CAN的UDS,就是基于ISO 14229-1协议。从下图中可以看到ISO 14229-1协议有不同的Service Id,可以支持不同的服务需求。

比如10表示可进行Diagnoistic Session Control操作,11表示可以对ECU进行Reset操作,27表示可进行Security Access操作等等。

此外还有一些sub-function,不同的sub-function支持不同的功能。比如说Security Access由两帧组成,假设01表示是访问seed,获取种子,在获取到种子之后发送,获取到解析的种子协议再返还回去才能够安全访问。

22表示读取数据信息,23表示可进行Memory By Address操作,19是读取故障码信息,14是清除故障码信息,还可以对ECU进行上传、下传数据等各种操作。

ISO 15031-5协议

基于排放标准的OBD协议,排放标准是ISO 15031协议共有七个章节,每个章节定义不同的内容,主要是以第五章为主。

排放标准的ISO 15031-5协议共有九个服务,不同的服务有不同的功能,在下图均都描述。

我们以Service$01: Request Current Powertrain Diagnostic data(请求动力系当前数据)来解析ISO 15031-5协议。

每一个PID表示一个传感器,也可以说表示一个数据流,数据流既有状态值,也有数据值。但并不是所有的车都支持所有的PID。首先访问00,如果ECU得到的数据用bit的形式来表示,如果是1表示支持当前的PID,0则表示不支持当前的PID。

所有基于排放标准的ECU,均支持Service$01,即请求动力系当前数据的D00组数据,也就是说如果想获取相关00组的数据,绝大部分车是支持的。

在获取支持有效PID后,就可以访问实际的PID值,每一次可以访问六个PID。

上图表示00组可以支持01—20组的PID,20可以支持21—40组的PID,以此类推。

上图表示发送0100后ECU的回复。回复41+40,01+40或41表示当前请求动力系当前数据,00表示访问PID获取有效的PID。可以看到第一个字节BF是1011111,即当前ECU支持PID的数据为01及03—08,这7个PID数据,以下类似。

在获取到有效的PID后,我们需要进一步读取当前PID的实际内容,每次最多可以读取六个PID值。15表示Bank 1 – Sensor 2,01表示当前的故障灯状态及故障码数量;05表示冷却液温度等等,如上图所示。

回复值的顺序与初始发送的数据并不一定相同,但是会先发送PID的组号,再补充PID当前组号的实际内容。通过上图可以知道,41表示请求动力帧回复;05表示冷却液温度;61表示冷却液温度的实际值,其他类似。

15031-5协议的Mode 1

上图为Mode 01中PID的一部分。第一列表示PID的序号,后面有不同数据流内容的描述。比如第一个是前文提到的故障码状态与故障码数量,PID2表示冻结的故障码,第三个是Fuel system status。12表示发动机转速,对于转速的最小值、最大值、单位、公式都有具体的规定。

汽车诊断协议的获取通常有三种方式获取骑车诊断协议:

  1. ISO 15031-5,由于目前所有车都支持ISO 15031-5协议,所以通过ISO 15031-5协议可以获取大部分的数据信息;
  2. 厂家原厂协议,适用于部分不在15031-5内,由厂家自行定义的协议;
  3. 第三方工具破解诊断协议。当拿不到原厂协议,需要获取的信息也不在ISO 15031-5里时,只能通过第三方工具进行破解,比如原厂诊断仪和综合诊断仪等。

原厂诊断仪:日产Consult诊断仪、丰田GTS诊断仪、本田HDS诊断仪、大众5053/5054诊断仪等。

综合诊断仪厂家:元征、金奔腾、朗仁、道通AUTEL、BOSCH等。

汽车诊断仪破解过程:

Step 1:

利用第3方工具采集实车诊断数据;

Step 2:

编写汽车模拟程序,即模拟汽车ECU和汽车诊断工序进行通讯;

Step 3:

破解诊断协议,目前基本上均为手动破解;

Step 4:

编写汽车诊断程序;

Step 5:

实车测试。

最新文章

  1. 为什么下载APP,扫描二维码,关注微信公众号,就会送牛奶送小礼品?下载使用量高,会怎样?
  2. MapReduce输入格式
  3. JavaScript封装Ajax(类JQuery中$.ajax()方法)
  4. Nutch配置:nutch-default.xml详解
  5. CentOS6.2编译安装codelite5.3
  6. codevs 2822爱在心中
  7. 常用的sql server规范
  8. 十分钟开发一个调用Activity的PhoneGap插件
  9. Delphi的组件读写机制
  10. MT过安全狗增加用户
  11. Spring Boot中通过CORS解决跨域问题
  12. C# -- 使用Ping检查网络是否正常
  13. W3C的标准到底是啥?
  14. JS基础学习1
  15. 4. Go常量
  16. Nmap 命令操作详解
  17. bzoj 2429: [HAOI2006]聪明的猴子 (最小生成树)
  18. Navicat for MYSQL 断网时本地连接无法打开,2005错误
  19. 各种HTTPS站点的SSL证书 ,扩展SSL证书,密钥交换和身份验证机制汇总
  20. Mac——mac安装软件

热门文章

  1. python3使用tkinter之Menu坑
  2. VS Code 的插件位置更改
  3. getopts的使用 + 创建空目录
  4. Gym - 100989 L / M 【dfs / dp】
  5. LESSON 6- Quantization
  6. 2019牛客暑期多校训练营(第七场)-B Irreducible Polynomial(多项式因式分解)
  7. [转帖]AMD第三代锐龙处理器首发评测:i9已无力招架
  8. 【转帖】.NET的一点历史故事:作者的一些感想
  9. 文件操作:w,w+,r,r+,a,wb,rb
  10. 怎样在 js 中实现 反转字符串 的功能?