系统越做越复杂,涉及到很多集成外设或者是外部功能模块的操作。这时需要对每个外设或功能模块编写相应的驱动程序,驱动程序编写是复杂系统模块化过程中一个很重要的环节。好坏与否关系系统的稳定性和模块的可重复利用性。
驱动程序是将外设抽象成与硬件无关操作的中间程序,因此驱动程序有两个重要问题要处理,一个是设备的操作流程处理,二是驱动函数调用时传递和返回值的处理。
由于应用程序层的函数希望通过调用驱动程序的方式使得应用程序与硬件无关,因此驱动函数的调用应该尽可能完成所有与硬件直接相关的操作流程,同时为应用程序提供必要的可变配置信息输入端口,以方便应用程序灵活调用。驱动程序的返回原则上应该是操作的状态信息,例如:是否成功,或故障代码。而数据传输应该以传入数据缓存区指针的方式完成。
一个设备的驱动程序应包含一下几个调用函数:
1、初始化函数
用于外设启动所需的电气连接操作,或设计IO端口配置,设备上电后配置操作等,在多任务系统中初始化操作还应包含所需信号量或消息等的创建。初始函数供应用函数在使用该设备时调用。初始化函数的参数一般为:设备号(如果相同的设备有多个的时候需要,这样可以有效重复利用驱动程序代码),必要参数(传输速率,工作模式等)。返回一般为:成功或不成功,简单操作或无法判断是否成功的情况下也可以不返回 。
例如:uart_Init(const S_BSP_UART *pUart,uint32 dBaudrate,uint32 dMode);
adc_Init(uint32 channel,uint8 trg,uint16 period);
key_Init(void);
2、读设备操作函数
用于从设备中获取数据,该函数应该包含这个读写过程所需的所有操作。确保应用程序在调用该程序后就能获得想要的数据,而不要在添加其他辅助操作或与硬件相关的操作。其参数一般为:设备号,数据缓存指针,欲读取数据长度等,返回:读取成功或不成功
例如:uart_GetData(const S_BSP_UART *pUart,uint8 *RecivBuf,uint16 timeout,uint16 size,uint16 *rsize);
adc_GetDatas(uint16 *buff,uint16 size);
3、写设备操作函数
用于向设备中写入数据,该函数应该包含这个读写过程所需的所有操作。确保应用程序在调用该程序后就能获得想要的数据,而不要在添加其他辅助操作或与硬件相关的操作。其参数一般为:设备号,数据缓存指针,欲写入数据长度等,返回:写入成功或不成功
例如:twi_Write(uint32 sla,uint32 suba,uint32 subasize,uint8 *data,uint32 len);
pwm_Set(S_PWM_DRIVER *pPwm,uint32 frequency,uint16 dutycycle,uint16 type);
4、中断处理函数
设备使用过程中需要使用到中断,需要编写中断处理函数,用来挂接到系统中断处理程序中。中断处理函数应尽可简短,不允许有等待信号量或消息等操作,不允许使用操作系统延时。中断处理函数应该处理最近紧急的事件或完成时序严格的操作,数据处理可以消息或信号的方式发自出来。该函数不返回,可带参数。
例如:uart_ISRHandler(const S_BSP_UART *pUart);
adc_ISRHandler(void);
5、设备IO操作函数
设备IO操作用于完成设备的控制性操作,例如关闭,休眠,待机,唤醒,擦除,删除等命令性动作。