文章目录[隐藏]
前言
- RT-Thread 的device框架,还是比较的实用的,可以用来对一些外设、模块进行【抽象】,这样底层驱动与上层应用可以降低耦合性。
- 默认RT-Thread的BSP工程,大部分都是一个流水灯控制,一般流水灯是通过GPIO引脚直接控制的。
- 这里使用rt_device的方法,把led注册成一个led device,通过device的API接口进行控制
学习rt_device
- rt_device 提供了较为通用的接口,可以实现对设备的初始化、读写、控制,当然,如果外设过于复杂,可以增加额外的ops,也就是可以自己定义一个device,继承rt_device。
- rt_device 主要的ops如下:
/* 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, int cmd, void *args);
- 可以通过自定义的cmd,充分利用device的control,来实现对设备的管理,如开关、配置等操作
LED改为Device设备
- 验证平台:NUCLEO-L476RG 开发板(STM32L476RG)
- LED : PA5引脚,高电平:亮 低电平:灭
- 抽象在软件设计中很有用,使用rt_device框架后,你会发现,上层应用可以与底层解耦,也就是上层应用只需要通过一个设备名称来访问控制设备,通过标准的device api 来操作设备,不用关心底层的改变。如果直接控制某个引脚,引脚改变后,应用就要一起更改。
- 使用框架的好处就是底层改变,上层不需要改变或只会很少的改变。
- 注册设备的代码如下:
led_dev.c
: led设备注册
#include "led_dev.h"
#include "board.h"
#define LED1_DEVICE_NAME "led1"
/* defined the LED0 pin: PA5 */
#define LED0_PIN GET_PIN(A, 5)
static struct rt_device _led_dev;
static rt_err_t _led_init(rt_device_t dev)
{
rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
return RT_EOK;
}
static rt_err_t _led_open(rt_device_t dev, rt_uint16_t oflag)
{
if (dev == RT_NULL)
return -RT_ERROR;
return RT_EOK;
}
static rt_err_t _led_close(rt_device_t dev)
{
if (dev == RT_NULL)
return -RT_ERROR;
return RT_EOK;
}
static rt_err_t _led_control(rt_device_t dev, int cmd, void *args)
{
if (dev == RT_NULL)
return -RT_ERROR;
switch (cmd)
{
case LED_CTRL_CMD_POWER_ON:
rt_pin_write(LED0_PIN, PIN_HIGH);
break;
case LED_CTRL_CMD_POWER_OFF:
rt_pin_write(LED0_PIN, PIN_LOW);
break;
default:
break;
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops led_dev_ops =
{
_led_init,
_led_open,
_led_close,
RT_NULL,
RT_NULL,
_led_control
};
#endif
static int led1_device_register(const char *name, void *user_data)
{
_led_dev.type = RT_Device_Class_Miscellaneous;
_led_dev.rx_indicate = RT_NULL;
_led_dev.tx_complete = RT_NULL;
#ifdef RT_USING_DEVICE_OPS
_led_dev.ops = &led_dev_ops;
#else
_led_dev.init = _led_init;
_led_dev.open = _led_open;
_led_dev.close = _led_close;
_led_dev.read = RT_NULL;
_led_dev.write = RT_NULL;
_led_dev.control = _led_control;
#endif
_led_dev.user_data = user_data;
/* register a character device */
rt_device_register(&_led_dev, name, RT_DEVICE_FLAG_RDWR);
return 0;
}
int led1_device_init(void)
{
return led1_device_register(LED1_DEVICE_NAME, RT_NULL);
}
led_dev.h
#ifndef __LED_DEV_H__
#define __LED_DEV_H__
#include <rtthread.h>
#include <rtdevice.h>
#define LED_CTRL_CMD_POWER_OFF 0x00
#define LED_CTRL_CMD_POWER_ON 0x01
int led1_device_init(void);
#endif
- led1_app.c : led 设备应用接口
#include "led1_app.h"
#ifndef LED1_DEVICE_NAME
#define LED1_DEVICE_NAME "led1"
#endif
static rt_device_t led1_dev = RT_NULL;
static rt_device_t get_led1_dev(void)
{
if (led1_dev != RT_NULL)
return led1_dev;
led1_dev = rt_device_find(LED1_DEVICE_NAME);
return led1_dev;
}
static rt_err_t led1_open(void)
{
rt_device_t dev = get_led1_dev();
if (dev == RT_NULL)
return -RT_ERROR;
return rt_device_open(dev, RT_DEVICE_FLAG_RDWR);
}
rt_err_t led_grn_init(void)
{
led1_device_init();
return led1_open();
}
rt_err_t led_grn_power_on(void)
{
rt_device_t dev = get_led1_dev();
if (dev == RT_NULL)
return -RT_ERROR;
return rt_device_control(dev, LED_CTRL_CMD_POWER_ON, RT_NULL);
}
rt_err_t led_grn_power_off(void)
{
rt_device_t dev = get_led1_dev();
if (dev == RT_NULL)
return -RT_ERROR;
return rt_device_control(dev, LED_CTRL_CMD_POWER_OFF, RT_NULL);
}
- led1_app.h
#ifndef __LED1_APP_H__
#define __LED1_APP_H__
#include "led_dev.h"
rt_err_t led_grn_init(void);
rt_err_t led_grn_power_on(void);
rt_err_t led_grn_power_off(void);
#endif
- main.c 初始化与功能验证
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include "drv_gpio.h"
#include "key.h"
#include "pms.h"
#include "led1_app.h"
int main(void)
{
key_gpio_init();
led_grn_init();
pms_task_init();
rt_thread_mdelay(1000);
#ifdef RT_USING_PM
rt_pm_module_delay_sleep(PM_POWER_ID, 10000);
//rt_pm_module_release(PM_POWER_ID, PM_SLEEP_MODE_NONE);
#endif
while (1)
{
led_grn_power_on(); /* LED ON */
rt_thread_mdelay(500);
led_grn_power_off(); /* LED OFF */
rt_thread_mdelay(500);
}
}
运行效果
msh >
\ | /
- RT - Thread Operating System
/ | \ 4.1.0 build Jan 16 2022 18:19:43
2006 - 2021 Copyright by rt-thread team
[D/key] key_gpio_init.
[D/key] PIN_KEY0=45
msh >
msh >
msh >
msh >list_device
device type ref count
-------- -------------------- ----------
led1 Miscellaneous Device 1 /* 注册的设备 */
uart2 Character Device 2
pin Miscellaneous Device 0
msh >
心得体会
- 注意rt_device设备,操作前先:
init
或open
- 使用device的方式,发现代码量变多了,有点复杂,看上去不如直接控制引脚来的方便,但是后期维护很容易
- 使用device的方式,可以很容易的扩展到其他外设的控制,如喇叭、电机等
- 如果只是控制一个led,确实有点浪费,通过修改可以用来控制一组LED
小结
- 学习掌握rt_device的框架的使用,了解使用的目的是为了上层应用于底层驱动的解耦。
- 了解抽象在软件设计中的作用。
版权声明:本文为CSDN博主「张世争」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tcjy1000/article/details/122530896
暂无评论