RT-Thread 学习笔记(六)——串口

串口设备结构体:

struct rt_serial_device
{
	struct rt_device          parent;

	const struct rt_uart_ops *ops;
	struct serial_configure   config;

	void *serial_rx;
	void *serial_tx;
};

RTT设备结构体:

struct rt_device
	{
		struct rt_object          parent;                   /**< inherit from rt_object */

		enum rt_device_class_type type;                     /**< device type */
		rt_uint16_t               flag;                     /**< device flag */
		rt_uint16_t               open_flag;                /**< device open flag */

		rt_uint8_t                ref_count;                /**< reference count */
		rt_uint8_t                device_id;                /**< 0 - 255 */

		/* device call back */
		rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
		rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);

		/* common device interface */
		rt_err_t (*init)(rt_device_t dev);
		rt_err_t (*open)(rt_device_t dev, rt_uint16_t oflag);
		rt_err_t (*close)(rt_device_t dev);
		rt_size_t (*read)(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
		rt_size_t (*write)(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
		rt_err_t (*control)(rt_device_t dev, rt_uint8_t cmd, void *args);

		void                     *user_data;                /**< device private data */
	};

串口初始化在rt_hw_usart_init()函数:

#if defined(RT_USING_UART3)
	uart = &uart3;
	config.baud_rate = BAUD_RATE_115200;
	serial3.ops    = &stm32_uart_ops;
	serial3.config = config;
	NVIC_Configuration(&uart3);
	/* register UART1 device */
	rt_hw_serial_register(&serial3, "uart3",
	                      RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
	                      uart);
#endif /* RT_USING_UART3 */
接着看一下串口注册rt_hw_serial_register():

rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
                               const char              *name,
                               rt_uint32_t              flag,
                               void                    *data)
{
	struct rt_device *device;
	RT_ASSERT(serial != RT_NULL);
	device = &(serial->parent);			//获取serial中parent成员的地址,并将地址赋值给device变量,之后操作device变量就是操作parent
	device->type        = RT_Device_Class_Char;
	device->rx_indicate = RT_NULL;
	device->tx_complete = RT_NULL;
	device->init        = rt_serial_init;
	device->open        = rt_serial_open;
	device->close       = rt_serial_close;
	device->read        = rt_serial_read;
	device->write       = rt_serial_write;
	device->control     = rt_serial_control;
	device->user_data   = data;
	/* register a character device */
	return rt_device_register(device, name, flag);
}
注册函数有四个参数:

参数1:所要注册的串口,参数类型为串口结构体

参数2:串口名

参数3:串口读写等标志位

参数4:串口私有数据

实际上,这个串口注册函数在最后return时,调用rt_device_register(),在系统注册一个字符设备,前面的操作为填充serial结构体中的parent成员。


看下系统设备的注册函数rt_device_register():

rt_err_t rt_device_register(rt_device_t dev,
                            const char *name,
                            rt_uint16_t flags)
{
	if (dev == RT_NULL)
	{ return -RT_ERROR; }


	if (rt_device_find(name) != RT_NULL)		//检查系统是否有重名,若有与name相同的设备则返回错误
	{ return -RT_ERROR; }


	rt_object_init(&(dev->parent), RT_Object_Class_Device, name);
	dev->flag = flags;
	dev->ref_count = 0;
	dev->open_flag = 0;
	return RT_EOK;
}

其参数为:

/**
 * This function registers a device driver with specified name.
 *
 * @param dev the pointer of device driver structure
 * @param name the device driver's name
 * @param flags the flag of device
 *
 * @return the error code, RT_EOK on initialization successfully.
 */
在串口注册函数中有此三个参数的接收,不再赘述。

在系统设备注册函数中还是有个重要的函数:rt_object_init();

初始化对象,并将该对象添加到对象管理系统。

/**
 * This function will initialize an object and add it to object system
 * management.
 *
 * @param object the specified object to be initialized.
 * @param type the object type.
 * @param name the object name. In system, the object's name must be unique.
 */
void rt_object_init(struct rt_object         *object,
                    enum rt_object_class_type type,
                    const char               *name)
{
	register rt_base_t temp;
	struct rt_object_information *information;
#ifdef RT_USING_MODULE
	/* get module object information */
	information = (rt_module_self() != RT_NULL) ?
	              &rt_module_self()->module_object[type] : &rt_object_container[type];
#else
	/* get object information */
	information = &rt_object_container[type];
#endif
	/* initialize object's parameters */
	/* set object type to static */
	object->type = type | RT_Object_Class_Static;
	/* copy name */
	rt_strncpy(object->name, name, RT_NAME_MAX);
	RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
	/* lock interrupt */
	temp = rt_hw_interrupt_disable();
	/* insert object into information object list */
	rt_list_insert_after(&(information->object_list), &(object->list));
	/* unlock interrupt */
	rt_hw_interrupt_enable(temp);
}

到这里就得说一下RTThread的设备框架了:(以下均为参考官方文档http://www.rt-thread.org/document/site/zh/1chapters/06-chapter_device/)


从系统框架结构图中可以看到,将I/O设备分为了三层,I/O设备管理模块对上层提供抽象的设备的操作接口,对底层驱动提供了一套驱动框架。

另外,RTThread的设备模型是建立在内核对象模型的基础之上的,设备也被当做是一类对象,纳入对象管理器。每个对象都由基对象派生而来,继承其父对象的基本属性,再派生出它自己的私有属性。(对象编程思想,看看java,写几个类就明白了)。我觉得下图中的基类改为基对象更贴切。


然后再回过头来看程序:rt_object_init()

首先看参数:

参数1:要被初始化的对象结构体

参数2:对象的类型

参数3:对象的名字,在系统内,此名称必须是独一无二的

首先先说参数3,从最开始的串口设备注册到现在,一直挂着这个参数,现在终于找到放到哪了,看对象结构体的定义:

struct rt_object
	{
		char       name[RT_NAME_MAX];                       /**< name of kernel object */
		rt_uint8_t type;                                    /**< type of kernel object */
		rt_uint8_t flag;                                    /**< flag of kernel object */

#ifdef RT_USING_MODULE
		void      *module_id;                               /**< id of application module */
#endif
		rt_list_t  list;                                    /**< list node of kernel object */
	};
看到没?看到没??看到没???第一个成员就是!!!

这个就是内核对象的基对象结构体,Base structure of Kernel object,自己翻译体会体会。

然后看第二个参数——队象的类型:

还是直接上代码:

/**
	 *  The object type can be one of the follows with specific
	 *  macros enabled:
	 *  - Thread
	 *  - Semaphore
	 *  - Mutex
	 *  - Event
	 *  - MailBox
	 *  - MessageQueue
	 *  - MemHeap
	 *  - MemPool
	 *  - Device
	 *  - Timer
	 *  - Module
	 *  - Unknown
	 *  - Static
	 */
	enum rt_object_class_type
	{
	    RT_Object_Class_Thread = 0,                         /**< The object is a thread. */
#ifdef RT_USING_SEMAPHORE
	    RT_Object_Class_Semaphore,                          /**< The object is a semaphore. */
#endif
#ifdef RT_USING_MUTEX
	    RT_Object_Class_Mutex,                              /**< The object is a mutex. */
#endif
#ifdef RT_USING_EVENT
	    RT_Object_Class_Event,                              /**< The object is a event. */
#endif
#ifdef RT_USING_MAILBOX
	    RT_Object_Class_MailBox,                            /**< The object is a mail box. */
#endif
#ifdef RT_USING_MESSAGEQUEUE
	    RT_Object_Class_MessageQueue,                       /**< The object is a message queue. */
#endif
#ifdef RT_USING_MEMHEAP
	    RT_Object_Class_MemHeap,                            /**< The object is a memory heap */
#endif
#ifdef RT_USING_MEMPOOL
	    RT_Object_Class_MemPool,                            /**< The object is a memory pool. */
#endif
#ifdef RT_USING_DEVICE
	    RT_Object_Class_Device,                             /**< The object is a device */
#endif
	    RT_Object_Class_Timer,                              /**< The object is a timer. */
#ifdef RT_USING_MODULE
	    RT_Object_Class_Module,                             /**< The object is a module. */
#endif
	    RT_Object_Class_Unknown,                            /**< The object is unknown. */
	    RT_Object_Class_Static = 0x80                       /**< The object is a static object. */
	};
第九个成员就是我们在操作的设备对象。
再说下参数1,说完继续干串口。。。。

参数1就是定义的串口设备serial的系统设备parent的基对象parent

简单来看就是serial->parent->parent

****************************************************************

下面干点无聊的事,把三个结构体放一起试试,我就是想这样玩。。。

struct rt_serial_device
{
	//struct rt_device          parent;
	{
		//struct rt_object          parent;                   /**< inherit from rt_object */
		
	{
		char       name[RT_NAME_MAX];                       /**< name of kernel object */
		rt_uint8_t type;                                    /**< type of kernel object */
		rt_uint8_t flag;                                    /**< flag of kernel object */

#ifdef RT_USING_MODULE
		void      *module_id;                               /**< id of application module */
#endif
		rt_list_t  list;                                    /**< list node of kernel object */
	};

		enum rt_device_class_type type;                     /**< device type */
		rt_uint16_t               flag;                     /**< device flag */
		rt_uint16_t               open_flag;                /**< device open flag */

		rt_uint8_t                ref_count;                /**< reference count */
		rt_uint8_t                device_id;                /**< 0 - 255 */

		/* device call back */
		rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
		rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);

		/* common device interface */
		rt_err_t (*init)(rt_device_t dev);
		rt_err_t (*open)(rt_device_t dev, rt_uint16_t oflag);
		rt_err_t (*close)(rt_device_t dev);
		rt_size_t (*read)(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
		rt_size_t (*write)(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
		rt_err_t (*control)(rt_device_t dev, rt_uint8_t cmd, void *args);

		void                     *user_data;                /**< device private data */
	}

	//const struct rt_uart_ops *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, const rt_uint8_t *buf, rt_size_t size, int direction);
	}
	//struct serial_configure   config;
	{
	rt_uint32_t baud_rate;


	rt_uint32_t data_bits               : 4;
	rt_uint32_t stop_bits               : 2;
	rt_uint32_t parity                  : 2;
	rt_uint32_t bit_order               : 1;
	rt_uint32_t invert                  : 1;
	rt_uint32_t bufsz					: 16;
	rt_uint32_t reserved                : 4;
	}

	void *serial_rx;
	void *serial_tx;
};


 
 

 这样咱们就可以看一看这个串口设备结构体里到底都是什么鬼了,看能看懂的,看不懂的放放,八成是你现在用不着的,用的着的时候再仔细研究。 
 

name,内核对象的名字,"uart3",系统独一无二的

type,对象的类型,RT_Object_Class_Device设备对象

open_flag,设备打开标志

reference,设备引用计数

device_id,设备id

两个回调函数:

rx_indicate

tx_complete

接下来,通用设备接口:

init

open

close

read

write

control

user_data:设备私有数据指针

下面一堆串口操作函数指针:

configure

control

putc

getc

dma_transmit

紧接着是串口配置信息,包括8N1,串口缓冲区大小等:

baud_rate

data_bits

stop_bits

parity

bit_order

invert

bufsz

下面是串口发送和接收区缓存地址指针:

serial_rx

serial_tx



先写这么多,还在学习中。。。

发布了14 篇原创文章 · 获赞 14 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/skawu/article/details/78531072