Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
KEY_按键
LED
rt-smart
smart 用户态按键点灯
发布于 2023-03-01 11:36:24 浏览:879
订阅该版
[tocm] ## 硬件环境 - RDC2022 纪念版开发板 ## 点亮 LED 灯 使用过 ART-Pi-smart 的应该都是从灵魂点灯开始的,关于 ART-Pi-smart 上的点灯程序驱动,应该都是使用的 `rt_device_control` `rt_device_write` 的形式来使用的,当然这种方式在 D1s 上也是可以的 下面就是一段 D1s 上的点灯程序,通过用户态编译,烧进开发板后即可运行 ```c #include
#include
#define GET_PIN(PORTx, PIN) (32 * (PORTx - 1) + (PIN & 31)) #define LED_PIN GET_PIN(7, 15) // PG15 /* 由于用户态没有定义这两个结构体,所以这里要重新定义一下,这里要和内核中的定义一直,否则将可能无法运行*/ struct rt_device_pin_mode { rt_base_t pin; rt_uint8_t mode; }; struct rt_device_pin_status { rt_base_t pin; rt_uint8_t status; }; int main() { rt_device_t pin_dev; struct rt_device_pin_mode pin_mode; struct rt_device_pin_status pin_status; pin_dev = rt_device_find("pin"); if (pin_dev == RT_NULL) { rt_kprintf("not find pin device!\n"); return -1; } rt_device_open(pin_dev, RT_DEVICE_OFLAG_RDWR); pin_mode.pin = LED_PIN; pin_mode.mode = 0; rt_device_control(pin_dev, 0, (void *)&pin_mode); pin_status.pin = LED_PIN; while (1) { pin_status.status = 0; rt_device_write(pin_dev, 0, (void *)&pin_status, sizeof(pin_status)); rt_thread_mdelay(200); pin_status.status = 1; rt_device_write(pin_dev, 0, (void *)&pin_status, sizeof(pin_status)); rt_thread_mdelay(200); } rt_device_close(pin_dev); return 0; } ``` 通过了解上述程序,可以发现 smart 用户态程序和 rt-thread 基本没有区别,这是由于为了方便用户上手 smart 已经将 rt-thread 部分 api 对接到了用户态中,当然这种开发方式并不适用于所有的 rt-thread api,有些还没有对接完成(就例如下文中提到的按键回调的绑定,由于用户态地址和内核态地址不同的原因,内核态并不能直接调用用户态的函数) 这样的话,又引出了另一种的开发方式,就是像 linux 一样,一切皆文件的形式来去开发,用户态方面使用 [DevFS 设备管理](https://download.rt-thread.org/ci-agent/artifacts/164823/452417/artifacts/docs-online/#/rt-thread-version/rt-thread-smart/device/DevFS/DevFS) 去开发设备,并且官方只推荐这种方式进行设备开发 ### 下面就是使用了 DevFS 进行开发的程序 这里分为两个部分 - 内核态设备注册 - 用户态驱动 #### LED 内核态设备注册 ```c #include
#include
#include
#include
#include
#define GET_PIN(PORTx, PIN) (32 * (PORTx - 1) + (PIN & 31)) #define USER_LED GET_PIN(7, 15) // PG15 static uint8_t is_init; static uint8_t led_state; static uint8_t led_state_old; static rt_device_t device; static void drv_led_init(void) { rt_pin_mode(USER_LED, PIN_MODE_OUTPUT); rt_pin_write(USER_LED, PIN_HIGH); } /* Open the led device, and initialize the hardware the first time you open it */ static int drv_led_open(struct dfs_fd *fd) { if (!is_init) { is_init = 1; /* Initialize the hardware */ drv_led_init(); } /* Increase reference count */ device->ref_count ++; return 0; } /* Close the led device, and reset the hardware when the device is no longer in use */ static int drv_led_close(struct dfs_fd *fd) { /* Reduced reference count */ device->ref_count --; /* Reset the hardware when the device is no longer in use */ if (device->ref_count == 0) { /* ... */ is_init = 0; } return 0; } /* Read led state */ static int drv_led_write(struct dfs_fd *fd, const void *buf, size_t count) { if(*(int *)buf == 0) rt_pin_write(USER_LED, PIN_HIGH); else rt_pin_write(USER_LED, PIN_LOW); return 1; } /* * Realize the fops variables. */ static struct dfs_file_ops drv_led_fops = { drv_led_open, drv_led_close, RT_NULL, RT_NULL, drv_led_write, RT_NULL, RT_NULL, RT_NULL, RT_NULL, }; /* * Key device initialization function. */ static int rt_hw_led_init(void) { rt_err_t ret; /* 1. Allocates memory for device structures, Use the calloc function */ device = rt_calloc(1, sizeof(struct rt_device)); if (device == RT_NULL) { return -1; } /* 2. Set to miscellaneous device */ device->type = RT_Device_Class_Miscellaneous; /* 3. register a led device */ ret = rt_device_register(device, "led0", RT_DEVICE_FLAG_RDONLY); if (ret != RT_EOK) { rt_free(device); return ret; } /* 4. set fops */ device->fops = &drv_led_fops; return ret; } /* Using below macro to export this function, the function will be called automatically after kernel startup */ INIT_DEVICE_EXPORT(rt_hw_led_init); ``` #### LED 用户态驱动 ```c #include
#include
#include
#include
#define LED0_DEVICE_PATH "/dev/led0" int main(void) { int led_fd; int value = 0; int count = 300; led_fd = open(LED0_DEVICE_PATH, O_RDWR); if (led_fd < 0) { printf("open device failed\n"); return -1; } while (1) { value = 1; write(led_fd, &value, 1); sleep(1); value = 0; write(led_fd, &value, 1); sleep(1); } close(led_fd); return 0; } ``` ## 按键控制 LED 上面我们写好了 LED 的内核设备注册和用户态代码,可是 LED 灯只能随时间闪动,是不受我们控制的,那么现在我们要使用按键来去控制 LED 等了 下面,我们来书写按键的内核设备注册代码 #### KEY 内核态设备注册 这里我们使用了 poll 来实现监测按键是否按下,有兴趣的可以查一下 poll 机制 ```c #include
#include
#include
#include
#include
#define GET_PIN(PORTx, PIN) (32 * (PORTx - 1) + (PIN & 31)) #define USER_KEY GET_PIN(7, 13) // PG13 static uint8_t is_init; static uint8_t key_state; static uint8_t key_state_old; static rt_device_t device; void irq_callback() { /* enter interrupt */ key_state = rt_pin_read(USER_KEY); rt_interrupt_enter(); rt_wqueue_wakeup(&(device->wait_queue), (void *)POLLIN); /* leave interrupt */ rt_interrupt_leave(); } static void drv_key_init(void) { key_state = 1; key_state_old = 1; rt_pin_mode(USER_KEY, PIN_MODE_INPUT); rt_pin_attach_irq(USER_KEY, PIN_IRQ_MODE_RISING_FALLING, irq_callback, RT_NULL); rt_pin_irq_enable(USER_KEY, PIN_IRQ_ENABLE); } /* Open the key device, and initialize the hardware the first time you open it */ static int drv_key_open(struct dfs_fd *fd) { if (!is_init) { is_init = 1; /* Initialize the hardware */ drv_key_init(); } /* Increase reference count */ device->ref_count ++; return 0; } /* Close the key device, and reset the hardware when the device is no longer in use */ static int drv_key_close(struct dfs_fd *fd) { /* Reduced reference count */ device->ref_count --; /* Reset the hardware when the device is no longer in use */ if (device->ref_count == 0) { /* ... */ is_init = 0; } return 0; } /* Read key state */ static int drv_key_read(struct dfs_fd *fd, void *buf, size_t count) { *(int *)buf = !rt_pin_read(USER_KEY); return 1; } /* Use poll to check the state of the key */ static int drv_key_poll(struct dfs_fd *fd, struct rt_pollreq *req) { int mask = 0; int flags = 0; /* only support POLLIN */ flags = fd->flags & O_ACCMODE; if (flags == O_RDONLY || flags == O_RDWR) { /* Add to wait queue, suspend the current thread */ rt_poll_add(&(device->wait_queue), req); /* If the key is pressed, mark a POLLIN event */ if (key_state != key_state_old) { key_state_old = key_state; mask |= POLLIN; } } return mask; } /* * Realize the fops variables. */ static struct dfs_file_ops drv_key_fops = { drv_key_open, drv_key_close, RT_NULL, drv_key_read, RT_NULL, RT_NULL, RT_NULL, RT_NULL, drv_key_poll, }; /* * Key device initialization function. */ static int rt_hw_key_init(void) { rt_err_t ret; /* 1. Allocates memory for device structures, Use the calloc function */ device = rt_calloc(1, sizeof(struct rt_device)); if (device == RT_NULL) { return -1; } /* 2. Set to miscellaneous device */ device->type = RT_Device_Class_Miscellaneous; /* 3. register a key device */ ret = rt_device_register(device, "key0", RT_DEVICE_FLAG_RDONLY); if (ret != RT_EOK) { rt_free(device); return ret; } /* 4. set fops */ device->fops = &drv_key_fops; return ret; } /* Using below macro to export this function, the function will be called automatically after kernel startup */ INIT_DEVICE_EXPORT(rt_hw_key_init); ``` #### 按键控制用户态驱动 上述完成了 KEY LED 的内核设备驱动注册,那么我们内核部分的操作就完成了,下面只需要在用户态对这两个设备进行 read write 等操作,就可以实现对按键和LED灯的控制了 ```c #include
#include
#include
#include
#define KEY0_DEVICE_PATH "/dev/key0" #define LED0_DEVICE_PATH "/dev/led0" int main(void) { int key_fd,led_fd; int value = 0; struct pollfd fds[1]; /* Open the device by non-blocking mode */ key_fd = open(KEY0_DEVICE_PATH, O_RDONLY | O_NONBLOCK); led_fd = open(LED0_DEVICE_PATH, O_RDWR); if (key_fd < 0 || led_fd < 0) { printf("open device failed\n"); return -1; } /* Add the key_fd to monitor */ fds[0].fd = key_fd; fds[0].events = POLLIN; while (1) { /* Monitor button status, timeout 1S */ if (poll(fds, 1, 1000) > 0 && fds[0].revents & POLLIN) { read(key_fd, &value, 1); write(led_fd, &value, 1); } } close(key_fd); close(led_fd); return 0; } ```
5
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
zhkag
这家伙很懒,什么也没写!
文章
12
回答
482
被采纳
66
关注TA
发私信
相关文章
1
应用开发如何包含头文件
2
STM32F03RC跑RTT标准版 没有运行
3
为什么 Count 的值不连续和间隔为 7?
4
请求LED.C/H文件
5
RT-thread 如何被当做“单片机”,控制小灯的亮灭?
6
ART-PI Smart User 运行LED 程序崩溃
7
agile led软件包怎么使用
8
AT32F423开发板呼吸灯无作用,只有一个灯亮
9
rt-smart发布时间
10
rt-smart qemu-vexpress-a9 编译报错
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
I2C_IIC
ESP8266
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
xusiwei1236
8
个答案
2
次被采纳
踩姑娘的小蘑菇
1
个答案
2
次被采纳
用户名由3_15位
7
个答案
1
次被采纳
bernard
4
个答案
1
次被采纳
RTT_逍遥
3
个答案
1
次被采纳
本月文章贡献
聚散无由
2
篇文章
15
次点赞
catcatbing
2
篇文章
5
次点赞
Wade
2
篇文章
3
次点赞
Ghost_Girls
1
篇文章
6
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部