硬物环境
RDC2022 纪念版开发板
点亮 LED 灯
Art-pi-smart的的都是是开始开始开始开始开始开始开始的开始开始开始开始灯灯开始开始rt_device_control rt_device_write点灯
下面就是一段D1s上的点灯程序,通过用户状态编译,燃烧打开发板后即可运行
#include <rtthread.h>
#include <stdio.h>
#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;
}
下面就是使用了DevFS 进行开发的程序
这里分为两个部分
内部状态设备注册
用户状态驱动
LED 内部状态设备注册
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <poll.h>
#include <dfs_file.h>
#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 用户态驱动
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#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灯只能随时间闪烁,是不受我们控制的,那么现在我们要用按键按键了
下面,我们来书按键的内核设备注册代码
KEY 内部状态设备注册
这里我们使用了poll 来实际监控按键是否按下,有兴趣的可以查一下poll机制
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <poll.h>
#include <dfs_file.h>
#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);
按键控制用户状态驱动
键led 的内核驱动,那么驱动设备内核操作就,下面完成了,下面部分,下面操作,下面只需要在用户态这两个设备
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#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;
}
原作者:zhkag