汉扬编程 编程大纲 嵌入式C语言中参数传递的实用技巧

嵌入式C语言中参数传递的实用技巧

我们在实际项目开发中,经常会封装一些API接口函数,以供别的模块调用。

比如,采用I2C总线连接的EEPROM驱动接口函数:

void Init_EE_I2C(void);unsigned char Write_EE_Byte(uint16_t addr, unsigned char tx_data);unsigned char Read_EE_Byte(uint16_t addr, unsigned char *data); I2C、SPI、UART等都属于单片机的常用总线。其中,I2C总线经常用来读写EEPROM。以上就是三个API接口函数分别实现了I2C总线的初始化、EEPROM写和EEPROM读。初始化 函数没什么好说的,没有参数也没有返回值,但是需要在EEPROM读写操作之前先被调用,以确定I2C总线的通信方式。

发送函数的一般定义方法

写函数,相当于把数据写入EEPROM,可以归到数据发送这一类API函数中,一般的定义方式如下,

发送状态 发送函数名(需要发送的数据)

/********************************************************************************************* 函数描述: 将8位数据写入到指定地址中* 输入参数: 1) addr,地址 2) tx_data,数据* 输出参数: 1) 执行结果,1为失败,0为成功* 注意事项: 1) 地址的实际有效位数与EEPROM的具体型号有关 2) 虽然tx_data为unsigned char类型,但也可输入负数,总之其输入范围为-128 ~ 255********************************************************************************************/unsigned char Write_EE_Byte(uint16_t addr, unsigned char tx_data){ unsigned long checkTicks = 0; addr = Restrict_int(addr, 0, MaxAddr); if (ReadyTask(addr)) { return 1; } I2C_SendData(EE_I2C, tx_data); //写一个字节 while (!I2C_CheckEvent(EE_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) { if (checkTicks > 10000000) { return 1; } checkTicks++; } checkTicks = 0; I2C_GenerateSTOP(EE_I2C, ENABLE); //发送停止位 if (I2C_Standby_24C()) { return 1; } return 0; }函数的返回值,一般作为函数执行状态的反馈,而不是直接用来输出参数。

比如,这里的发送状态的返回,针对执行结果,可以用1表示失败,0表示成功。至于其中失败的状态,其实可以根据具体原因再做细分,便于错误分析。

这里给出一个系统错误定义的实例:

#define Err_NoError 0 //没有错误#define Err_USBFailedToInit 252 //USB模块初始化失败#define Err_DiskFailedToCheckCapacity 253 //无法检查磁盘剩余空间#define Err_DiskNotEnoughSpace 254 //磁盘剩余空间不够#define Err_DiskUnknownType 255 //磁盘初始化失败#define Err_FileFailedToCreate 245 //文件创建失败#define Err_FileFailedToSetCreateTime 244 //无法设置文件创建时间#define Err_FileFailedToWrite 243 //文件写入失败#define Err_FileFailedToClose 242 //文件关闭失败#define Err_FlashFailedToInit 230 //flash初始化失败#define Err_FlashFailedToSave 231 //flash保存失败#define Err_DS18B20DonotExist 220 //DS18B20不存在#define Err_AM2303DonotExist 210 //AM2303不存在#define Err_AM2303FailedToTest 211 //AM2303数据检验失败#define Err_EEPROMFailedToInit 200 //EEPROM初始化失败#define Err_EEPROMFailedToLoad 201 //EEPROM加载参数失败以上是一种常用的错误状态的定义方法,当然遇到不同的情况还需要有不同的错误状态的定义。

接收函数的一般定义方法

读函数,相当于把EEPROM中的数据回读,可以归到数据接收这一类API函数中,一般的定义方式如下,

发送状态 接收函数名(用来装载回读数据的指针)

/********************************************************************************************* 函数描述: 从指定地址中读出一个字节的数据* 输入参数: 1) addr,地址 2) data,存放读取结果的指针* 输出参数: 1) 执行结果,1为失败,0为成功* 注意事项: 1) 地址的实际有效位数与EEPROM的具体型号有关 2) 虽然data类型为unsigned char *,但实际上可为char *,最终其表示范围根据指针类型 而定,例如,如果为unsigned char *,则范围为0~255,如果为char *,则范围为-128 ~ 127********************************************************************************************/unsigned char Read_EE_Byte(uint16_t addr, unsigned char *data){ unsigned long checkTicks = 0; addr = Restrict_int(addr, 0, MaxAddr); while (I2C_GetFlagStatus(EE_I2C, I2C_FLAG_BUSY)) //等待I2C总线空闲 { if (checkTicks > 10000000) { return 1; } checkTicks++; } checkTicks = 0; I2C_AcknowledgeConfig(EE_I2C, ENABLE); I2C_GenerateSTART(EE_I2C, ENABLE); //发送起始位 while (!I2C_CheckEvent(EE_I2C, I2C_EVENT_MASTER_MODE_SELECT)) { if (checkTicks > 10000000) { return 1; } checkTicks++; } checkTicks = 0; I2C_Send7bitAddress(EE_I2C, EEPROM_ADDR, I2C_Direction_Transmitter); //发送EEPROM器件地址 while (!I2C_CheckEvent(EE_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) { if (checkTicks > 10000000) { return 1; } checkTicks++; } checkTicks = 0; I2C_SendData(EE_I2C, (uint8_t)(addr & 0x00FF)); //先发送EEPROM存储单元的地址低8位 while (!I2C_CheckEvent(EE_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) { if (checkTicks > 10000000) { return 1; } checkTicks++; } checkTicks = 0; I2C_GenerateSTART(EE_I2C, ENABLE); //重新发送起始位 while (!I2C_CheckEvent(EE_I2C, I2C_EVENT_MASTER_MODE_SELECT)) { if (checkTicks > 10000000) { return 1; } checkTicks++; } checkTicks = 0; I2C_Send7bitAddress(EE_I2C, EEPROM_ADDR, I2C_Direction_Receiver); //发送EEPROM器件地址 while (!I2C_CheckEvent(EE_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) { if (checkTicks > 10000000) { return 1; } checkTicks++; } checkTicks = 0; I2C_AcknowledgeConfig(EE_I2C, DISABLE); //发送非应答位 I2C_GenerateSTOP(EE_I2C, ENABLE); //发送停止位 while (!I2C_CheckEvent(EE_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED)) { if (checkTicks > 10000000) { return 1; } checkTicks++; } checkTicks = 0; *data = I2C_ReceiveData(EE_I2C); I2C_AcknowledgeConfig(EE_I2C, ENABLE); //发送应答位 return 0;}与发送函数最大的不同就是,函数的参数。

一个传递的变量本身,一个传递的变量的指针。

关于这一点需要特别注意,不要搞混了。这也就是我们经常说的,C语言中传值和传址的问题。传值方式的参数本身在函数内的修改在函数结束后不会被保存,而传址方式的参数在函数内的修改在函数结束后被保存了下来。

其实函数的参数,不光是用来做输入的,有时候也是需要用来做输出的。发送函数,只需要将相关数据发送出去,并不需要改变发送数据本身,因此采用传值的方法;接收函数,实际需要的是,我们传入一个数据容器进去,再在接收函数中去承载所接收到数据,并作为输出参数输出,因此采用传址的方法。

实际上从严格的意义上来说函数的参数传递全部都是值传递,没有所谓的地址传递,参数本身在函数中的修改都是不会被保存的,因为进入函数时,参数的值都会被复制一个备份来在函数中使用,而不是直接使用参数,这样可以保证参数的值在退出函数时不会发生变化。所谓的传地址方式,实际上是将指针作为参数传递,那么参数实际上一个指针,也就是一个内存单元的地址(一个32位的整数),而不是参数所指向的内存单元的值,因此在函数中指针本身是被保护的,而指针所指向的内存单元的值并不是参数,它没有被作为参数来保护,从而可以被修改。

小结

所以说,函数的返回值,我们一般只用来反馈函数的执行状态;至于函数的参数,既可以作为输入参数、也可以作为输出参数。作为输入参数时,我们往往需要保护其原来的值不被修改,而传递其本身;作为输入参数时,我们这时候又需要保留其在函数内部变化,而传递它的指针。

本文来自网络,不代表汉扬编程立场,转载请注明出处:http://www.hyzlch.com/mianfei/6097.html

C语言中函数参数传递的三种方式

嵌入式C语言基础编程——5年程序员给你讲解结构体,精品干货

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

返回顶部