硬件环境
rdc2022 纪念版开发板
点亮 led 灯
使用过 art-pi-smart 的应该都是从灵魂点灯开始的,关于 art-pi-smart 上的点灯程序驱动,应该都是使用的 rt_device_control rt_device_write 的形式来使用的,当然这种方式在 d1s 上也是可以的
下面就是一段 d1s 上的点灯程序,通过用户态编译,烧进开发板后即可运行
#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 设备管理 去开发设备,并且官方只推荐这种方式进行设备开发
下面就是使用了 devfs 进行开发的程序
这里分为两个部分
内核态设备注册
用户态驱动
led 内核态设备注册
#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 用户态驱动
#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 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灯的控制了#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 && fds[0].revents & pollin)
{
read(key_fd, &value, 1);
write(led_fd, &value, 1);
}
}
close(key_fd);
close(led_fd);
return 0;
}
华为荣耀Note8、小米Max2对比评测:华为荣耀Note8和小米Max2谁才是大屏手机的佼佼者?
中国移动公布了5G小基站第一阶段研发项目采购中标结果
荷兰对华半导体设备出口额10月激增超100%
四维图新车载胎压监测芯片获集成电路布图设计登记证书
赛灵思“觉醒”:新任 CEO 透露聚焦软件,对标英伟达、英特尔
使用ART-Pi-smart用户态按键点灯
千元手机三大代表,红米魅蓝和荣耀
MySQL数据库误删后的回复技巧
人工智能的发展已经影响到了人类生活的各个领域
压接引脚的系统设计优势
权威机构实证荣耀Earbuds 2 SE续航超32小时 未来每月荣耀将推出重量级产品
浅谈内置STO安全电路功能
稳如磐石,强势崛起:国产工控主板引领工业控制新浪潮
台达UPS:通信领域的常青树
收购东芝发力医疗 佳能对CMOS技术是自信还是盲目
百度发布AI输入法 开创全感官输入2.0时代
iPhone投屏软件有哪些?苹果手机怎么投屏电脑?
燃料电池双极板产业现状如何
电子后视镜正式获批,车载摄像头、显示屏迎来新增长点!
基于天翼1号2021的5G切片创新应用完成端到端现网验证