RT-Thread驱动之路:stm32设备驱动开发之uart设备创建②


      开篇分割线:我们再写驱动程序的目的是能够注册到系统的框架之中,那么就在创建设备之初你的设备结构体(C++中叫类)必须从系统提供的结构中进行派生出新的结构体,根据自己的设备类型定义私有数据域,

      MCU一般会有多个串口,所以串口驱动也需要支持多个串口的配置,设备结构体更应该以数组的形式出现,config信息就代表了真实的硬件有多少个固定的串口,并通过数组一次性默认配置好,至于是不是要启用,可以通过预定义宏的方式进行开关:


      有了uart设备对象以后,我们还有需要能够操作对象的方法(C++中的类就集成了这一部分),C语言中可以通过函数指针的方式来实现操作方法的结构体存储:

/**
 * uart operators
 */
struct rt_uart_ops
{
    rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg);
    rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg);

    int (*putc)(struct rt_serial_device *serial, char c);
    int (*getc)(struct rt_serial_device *serial);

    rt_size_t (*dma_transmit)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction);
};

      上面定义的是函数原型的指针:后续需要我们根据stm32实现具体的方法来赋值给对应的原形,这里先说下每个函数的作用该实现怎样的功能,后续你才好去写这部分功能。

configure方法:用于配置串口的波特率、数据位、校验位、停止位等参数。

control方法:用于控制串口。

putc方法:用于串口向外发送字符数据。

getc方法:用于串口获取接收外部的字符数据。

transmit方法:用于数据发送侧重于多个字节的数据发送。

      你是否发现了一个很奇怪的参数,就是这些操作方法的第一个输入参数是系统提供的serial的结构体,按理说这里的ops需要进行最底层的硬件操作及数据收发,那为什么会是serial,而不是uart呢,其实这源于这些操作函数的调用方,假如应用和驱动不是分离的,那么应用可以很简单的知道底层的驱动是哪个uart,但实际上应用和驱动是隔离开的,应用需要通过一个名称来获取串口的句柄,而串口的句柄只能来自于系统的定义,也就是serial对象,但是我们实际上需要的是uart,那么这里提前引入一个转换,由成员对象找到派生对象的操作,不得不说C语言的强大,详细的分析会放到configure函数的实现上来讲:

/**
 * rt_container_of - return the member address of ptr, if the type of ptr is the
 * struct type.
 */
#define rt_container_of(ptr, type, member) \
    ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 4
收藏 5
关注 130
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧