养成好习惯,让代码更美观

一,引言

        作为一名嵌入式爱好者,每天都会面对各种风格的开源代码。有时好不容易找到了一个匹配自己的项目,但打开一看——这写的啥玩意?代码缩成一团,还没个标注。还有文件夹,代码乱七八糟地堆放在文件夹里,可能只有发布者一个人知道这些文件都是些啥玩意儿吧。咱们既然要开源,代码、文件啥的就得美观一点,再写个README文件,让没有用过自己文件体系的开发者知道该怎么用。

二,代码

(1)代码本身

        以九轴传感器获取代码为例。

void NineAxis_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
						int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ,
							int16_t *GaX, int16_t *GaY, int16_t *GaZ)
{
	uint8_t DataH, DataL;								
	
	DataH = NineAxis_ReadReg(MPU6050_ACCEL_XOUT_H);		
	DataL = NineAxis_ReadReg(MPU6050_ACCEL_XOUT_L);		
	*AccX = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_ACCEL_YOUT_H);		
	DataL = NineAxis_ReadReg(MPU6050_ACCEL_YOUT_L);		
	*AccY = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_ACCEL_ZOUT_H);		
	DataL = NineAxis_ReadReg(MPU6050_ACCEL_ZOUT_L);		
	*AccZ = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_GYRO_XOUT_H);		
	DataL = NineAxis_ReadReg(MPU6050_GYRO_XOUT_L);		
	*GyroX = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_GYRO_YOUT_H);	
	DataL = NineAxis_ReadReg(MPU6050_GYRO_YOUT_L);		
	*GyroY = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_GYRO_ZOUT_H);		
	DataL = NineAxis_ReadReg(MPU6050_GYRO_ZOUT_L);		
	*GyroZ = (DataH << 8) | DataL;								
	
	DataH = NineAxis_ReadReg(MPU6050_EXT_SENS_DATA_00);		
	DataL = NineAxis_ReadReg(MPU6050_EXT_SENS_DATA_01);		
	*GaX = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_EXT_SENS_DATA_02);		
	DataL = NineAxis_ReadReg(MPU6050_EXT_SENS_DATA_03);		
	*GaY = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_EXT_SENS_DATA_04);		
	DataL = NineAxis_ReadReg(MPU6050_EXT_SENS_DATA_05);		
	*GaZ = (DataH << 8) | DataL;	
}

        可以看到,这段代码让人感觉很整齐,很有层次。不难发现,能给我们带来这样的感受,是因为它做到了三件事:

        第一件,单行代码不过长

        可以看到函数名那一行,将三类参数分成了三行,如果它们就用一行表示,那么就会是下面的情况:

void NineAxis_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ,int16_t *GaX, int16_t *GaY, int16_t *GaZ)

        特别是在平台上读一些开发者的代码时,出现这样的情况,需要读一点,翻一下,很搞人心态啊,特别对于我这种记忆力不好的人来说。:(

        第二件,同类代码模块化

        我们将代码提行,并不是写一行空一行,而是“模块化”。这样说也许有些抽象,不过我们看到上面的代码内容部分:

    uint8_t DataH, DataL;								
	
	DataH = NineAxis_ReadReg(MPU6050_ACCEL_XOUT_H);		
	DataL = NineAxis_ReadReg(MPU6050_ACCEL_XOUT_L);		
	*AccX = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_ACCEL_YOUT_H);		
	DataL = NineAxis_ReadReg(MPU6050_ACCEL_YOUT_L);		
	*AccY = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_ACCEL_ZOUT_H);		
	DataL = NineAxis_ReadReg(MPU6050_ACCEL_ZOUT_L);		
	*AccZ = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_GYRO_XOUT_H);		
	DataL = NineAxis_ReadReg(MPU6050_GYRO_XOUT_L);		
	*GyroX = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_GYRO_YOUT_H);	
	DataL = NineAxis_ReadReg(MPU6050_GYRO_YOUT_L);		
	*GyroY = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_GYRO_ZOUT_H);		
	DataL = NineAxis_ReadReg(MPU6050_GYRO_ZOUT_L);		
	*GyroZ = (DataH << 8) | DataL;								
	
	DataH = NineAxis_ReadReg(MPU6050_EXT_SENS_DATA_00);		
	DataL = NineAxis_ReadReg(MPU6050_EXT_SENS_DATA_01);		
	*GaX = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_EXT_SENS_DATA_02);		
	DataL = NineAxis_ReadReg(MPU6050_EXT_SENS_DATA_03);		
	*GaY = (DataH << 8) | DataL;						
	
	DataH = NineAxis_ReadReg(MPU6050_EXT_SENS_DATA_04);		
	DataL = NineAxis_ReadReg(MPU6050_EXT_SENS_DATA_05);		
	*GaZ = (DataH << 8) | DataL;	

        函数定义处是一个模块,每个数据的高低位读取又各是一个模块,像这样,把每个模块单独提行,就会让代码层次分明。

        第三件,空格

        小小的空格,大大的用处,我们摘一段:

    //不空格
    DataH=NineAxis_ReadReg(MPU6050_GYRO_XOUT_H);		
	DataL=NineAxis_ReadReg(MPU6050_GYRO_XOUT_L);		
	*GyroX=(DataH<<8)|DataL;						
	
    //空格
    DataH = NineAxis_ReadReg(MPU6050_GYRO_XOUT_H);		
	DataL = NineAxis_ReadReg(MPU6050_GYRO_XOUT_L);		
	*GyroX = (DataH << 8) | DataL;						
	

        “高下立判”,我只能说——在一些运算符号左右空格,会大大提升美观度。

(2)注释

        很多初学者不知道如何写注释——写注释,只需要掌握核心要点——给我们自己起的名字写说明

        比如说上面的代码,uint8_t,看到这个符号,大家都知道接下来你要定义参数,就不需要写注释,而后面的DataH = NineAxis_ReadReg(),我们看起来,也许觉得很清楚——函数名都是用的英文简写。但是没有接触过这些代码的人不一定知道呀,此时,这段代码就是“我们自己起的名字”,我们就需要给它加上注释,如下:

    DataH = NineAxis_ReadReg(MPU6050_ACCEL_XOUT_H);		//读取加速度计X轴的高8位数据
	DataL = NineAxis_ReadReg(MPU6050_ACCEL_XOUT_L);		//读取加速度计X轴的低8位数据
	*AccX = (DataH << 8) | DataL;						//数据拼接,通过输出参数返回    

        这样,看的人就会知道,这里是在读数据,这里是在拼接数据。

三,文件

(1)文件夹

        对于文件,主要是在文件夹的创建与归类方面,以下是稚晖君大佬Dummy项目的文件夹:

        可以看到,文件夹中有编号,有文件类型,看上图所示的文件夹,就不会出现“凭运气找文件”的情况。

(2)README文件

        最后,我们来看看README文件,在文件内,说明自己的文件体系,操作方法等。我们摘取一段Dummy的README说明:

**主要改进如下:**

1. 使用C++11重构了代码,引入很多高级语言特性,同时底层部分用C混编,不影响代码性能
2. 对硬件依赖完全解耦了,可以方便以后移植到其他平台的MCU,去除了冗余代码代码也结构化逻辑更加清晰
3. 添加了CAN协议和UART协议的自定义模板
4. 添加了模拟EEPROM的参数储存,可以断电保存数据
5. 添加了任意位置设置为零点,且保证双向半圈内归零(而不是单向归零)
6. 完全兼容STM32-HAL库,可以使用STM32CubeMX直接生成配置代码
7. 其他改进,大家二次开发仅需关注UserApp文件夹下的文件即可

Ctrl-Step驱动的使用方式比较简单,下载好固件后,第一次上电电机会进行编码器校准,如果成功则下次上电后按下按键1会进入闭环模式,通过CAN或者串口发送指令即可控制电机,关于指令的说明见源代码`UserApp`文件夹的`interface_can.cpp`和`interface_uart.cpp`:

![](5.Docs/1.Images/fw3.png)

> 其他按键的作用:
>
> * 同时按住两个按键上电,会自动进行编码器校准,如果首次校准失败可以通过这个方式重新校准
> * 短按按键1在**使能闭环/失能闭环**间切换
> * 长按按键1板子重启
> * 短按按键2清除堵转保护
> * 长按按键2将目标值归零(比如如果是在位置模式那位置会归零)
>
> 其他的功能要通过代码或者通信协议设置,比如设置**home零点**、**PID参数**、CAN节点ID、**各种运动参数**等等,可以自己研究代码。

当然另一种方式是大家也可以自行使用GRBL类的驱动器改装用来驱动本机械臂,这样方案的问题在于,grbl固件耦合性比较强(毕竟不是针对机械臂而是CNC类应用设计的)不便于扩展,另外脉冲形式的控制方式使得走线极其不优雅(每一个关节都要单独拉`step/dir`线到控制器,导致最后几个关节走线很长)。

而我用一体闭环的方式则可以以串联的形式把所有电机连起来即可,走CAN总线使得整体走线只需要四根线(电源正负两根,CAN信号线两根),此外总线模型使得电机可以工作在`力矩`、`速度`、`位置`、`轨迹`模式下,而脉冲模式只能工作在位置和轨迹模式,无法进行复杂控制。

        这是驱动器PCB电路的改进,它体现了PCB的改进方法,关键元件的作用等。我们能够根据说明决定是否使用改进后的PCB电路,以及明确关键元件的作用。这样多清晰!

四,总结

        总结一下,想要让代码更加美观,需要注意以下几点:

        1,代码本身注意空格、模块化、单行长度

        2,对于容易让别人误解的段落,需要写上注释

        3,文件夹分类要清晰

        4,README文件对操作方案进行说明

欢迎交流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值