当前位置: 首页 > news >正文

上海网站建设科技公司做网站手机模板app

上海网站建设科技公司,做网站手机模板app,wordpress 页面路由,一朋友做网站网站被抓了Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 在人类的发展进化中#xff0c;时间是一个非常重要神秘的物质量。任何事物都是在时间的长河中流淌发生、发展、变化。我们进行驱动开发中对时间的定义和使用也是…Linux版本号4.1.15   芯片I.MX6ULL                                    大叔学Linux    品人间百味  思文短情长  在人类的发展进化中时间是一个非常重要神秘的物质量。任何事物都是在时间的长河中流淌发生、发展、变化。我们进行驱动开发中对时间的定义和使用也是必须要掌握的重要知识点。 本节笔记主要学习Linux内核定时器的驱动开发主要包括内核时间管理和定时器、硬件原理图分析【LED】、驱动开发和测试。最重要的内容为定时器驱动开发部分。 本笔记的脑图如下 一、Linux时间管理和内核定时器 1.内核时间管理 作为一个应用者不需要研究太深的具体实现。会用相应的API函数即可。 图形化配置界面可以设置系统节拍率。具体路径为 Kernel Features Timer frequency(choice[y]) 使用CONFIG_HZ来设置自己的系统时钟。 HZ表示一秒的节拍数也就是频率。 使用jiffies来记录系统从启动以来的系统节拍数。 jiffies/HZ就是系统运行时间单位为秒。 处理32位jiffies的绕回用到的几个函数。如下 函数        描述time_after(unknown,known)unkonwn超过known时为真time_before(unknown,known)unkonwn没有超过known时为真time_after_eq(unknown,known)unkonwn超过或等于known时为真time_before_eq(unknown,known)unkonwn没有超过或等于known时为真 2.内核定时器 需要周期性处理的工作都要用到定时器。Linux定时器采用系统时钟来实现只需要提供超时时间和定时处理函数即可。 内核定时器超时会自动关闭。 使用timer_list结构体表示内核定时器。该结构体的定义如下 struct timer_list { struct list_head entry; unsigned long expires; /* 定时器超时时间单位是节拍数 */ struct tvec_base *base; void (*function)(unsigned long); /* 定时处理函数 */ unsigned long data; /* 要传递给 function 函数的参数 */ int slack; }; 定义好定时器以后需要以下函数对其进行初始化 函数说明init_timer初始化add_timer注册del_timer删除del_timer_sync等待其他处理器使用完定时器后删除mod_timer修改定时值 内核定时器的使用流程如下 1 struct timer_list timer; /* 定义定时器 */ 2 3 /* 定时器回调函数 */ 4 void function(unsigned long arg) { 6 /* 7 * 定时器处理代码 8 */ 9 10 /* 如果需要定时器周期性运行的话就使用 mod_timer 11 * 函数重新设置超时值并且启动定时器。 12 */ 13 mod_timer(dev-timertest, jiffies msecs_to_jiffies(2000)); 14 } 15 16 /* 初始化函数 */ 17 void init(void) 18 { 19 init_timer(timer); /* 初始化定时器 */ 20 21 timer.function function; /* 设置定时处理函数 */ 22 timer.expiresjffies msecs_to_jiffies(2000);/* 超时时间 2 秒 */ 23 timer.data (unsigned long)dev; /* 将设备结构体作为参数 */ 24 25 add_timer(timer); /* 启动定时器 */ 26 } 27 28 /* 退出函数 */ 29 void exit(void) 30 { 31 del_timer(timer); /* 删除定时器 */ 32 /* 或者使用 */ 33 del_timer_sync(timer); 34 } 3.Linux内核短延时函数 函数 描述 void ndelay(unsigned long nsecs)      纳秒 void udelay(unsigned long usecs)      微秒 void mdelay(unsigned long mseces)  毫秒 二、硬件原理图分析 LED0 接到了 GPIO_3 上 GPIO_3 就是 GPIO1_IO03当 GPIO1_IO03输出低电平(0)的时候发光二极管 LED0 就会导通点亮当 GPIO1_IO03 输出高电平(1)的时候发光二极管 LED0 不会导通因此 LED0 也就不会点亮。所以 LED0 的亮灭取决于 GPIO1_IO03的输出电平输出 0 就亮输出 1 就灭。 三、驱动程序开发 1.修改设备树文件 使用已有的即可。 2.定时器驱动程序开发 38 struct timer_dev{ 39 dev_t devid; /* 设备号 */ 40 struct cdev cdev; /* cdev */ 41 struct class *class; /* 类 */ 42 struct device *device; /* 设备 */ 43 int major; /* 主设备号 */ 44 int minor; /* 次设备号 */ 45 struct device_node *nd; /* 设备节点 */ 46 int led_gpio; /* key 所使用的 GPIO 编号 */ 47 int timeperiod; /* 定时周期,单位为 ms */ 48 struct timer_list timer; /* 定义一个定时器 */ 49 spinlock_t lock; /* 定义自旋锁 */ 50 }; 定时器设备结构体在 48 行定义了一个定时器成员变量 timer。 60 static int led_init(void) 61 { 62 int ret 0; 63 64 timerdev.nd of_find_node_by_path(/gpioled); 65 if (timerdev.nd NULL) { 66 return -EINVAL; 67 } 68 69 timerdev.led_gpio of_get_named_gpio(timerdev.nd ,led-gpio, 0); 70 if (timerdev.led_gpio 0) { 71 printk(cant get led\r\n); 72 return -EINVAL; 73 } 74 75 /* 初始化 led 所使用的 IO */ 76 gpio_request(timerdev.led_gpio, led); /* 请求 IO */ 77 ret gpio_direction_output(timerdev.led_gpio, 1); 78 if(ret 0) { 79 printk(cant set gpio!\r\n); 80 } 81 return 0; 82 } LED 灯初始化函数从设备树中获取 LED 灯信息然后初始化相应的 IO。 91 static int timer_open(struct inode *inode, struct file *filp) 92 { 93 int ret 0; 94 filp-private_data timerdev; /* 设置私有数据 */ 95 96 timerdev.timeperiod 1000; /* 默认周期为 1s */ 97 ret led_init(); /* 初始化 LED IO */ 98 if (ret 0) { 99 return ret; 100 } 101 return 0; 102 } 函数 timer_open对应应用程序的 open 函数应用程序调用 open 函数打开/dev/timer 驱动文件的时候此函数就会执行。此函数设置文件私有数据为 timerdev并且初始化定时周期默认为 1 秒最后调用 led_init 函数初始化 LED 所使用的 IO。 111 static long timer_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 112 { 原子哥在线教学:www.yuanzige.com 论坛:www.openedv.com 1228 I.MX6U 嵌入式 Linux 驱动开发指南 113 struct timer_dev *dev (struct timer_dev *)filp-private_data; 114 int timerperiod; 115 unsigned long flags; 116 117 switch (cmd) { 118 case CLOSE_CMD: /* 关闭定时器 */ 119 del_timer_sync(dev-timer); 120 break; 121 case OPEN_CMD: /* 打开定时器 */ 122 spin_lock_irqsave(dev-lock, flags); 123 timerperiod dev-timeperiod; 124 spin_unlock_irqrestore(dev-lock, flags); 125 mod_timer(dev-timer, jiffies msecs_to_jiffies(timerperiod)); 126 break; 127 case SETPERIOD_CMD: /* 设置定时器周期 */ 128 spin_lock_irqsave(dev-lock, flags); 129 dev-timeperiod arg; 130 spin_unlock_irqrestore(dev-lock, flags); 131 mod_timer(dev-timer, jiffies msecs_to_jiffies(arg)); 132 break; 133 default: 134 break; 135 } 136 return 0; 137 } 函数 timer_unlocked_ioctl对应应用程序的 ioctl 函数应用程序调用 ioctl函数向驱动发送控制信息此函数响应并执行。此函数有三个参数 filp cmd 和 arg其中 filp是对应的设备文件 cmd 是应用程序发送过来的命令信息 arg 是应用程序发送过来的参数在本章例程中 arg 参数表示定时周期。 CLOSE_CMD 关闭定时器命令 调用 del_timer_sync 函数关闭定时器。OPEN_CMD打开定时器命令调用 mod_timer 函数打开定时器定时周期为 timerdev 的 timeperiod 成员变量定时周期默认是 1 秒。SETPERIOD_CMD设置定时器周期命令参数 arg 就是新的定时周期设置 timerdev 的 timeperiod 成员变量为 arg 所表示定时周期指。并且使用 mod_timer 重新打开定时器使定时器 以新的周期运行。   139 /* 设备操作函数 */ 140 static struct file_operations timer_fops { 141 .owner THIS_MODULE, 142 .open timer_open, 143 .unlocked_ioctl timer_unlocked_ioctl, 144 }; 定时器驱动操作函数集 timer_fops。   146 /* 定时器回调函数 */ 147 void timer_function(unsigned long arg) 148 { 149 struct timer_dev *dev (struct timer_dev *)arg; 150 static int sta 1; 151 int timerperiod; 152 unsigned long flags; 153 154 sta !sta; /* 每次都取反实现 LED 灯反转 */ 155 gpio_set_value(dev-led_gpio, sta); 156 157 /* 重启定时器 */ 158 spin_lock_irqsave(dev-lock, flags); 159 timerperiod dev-timeperiod; 160 spin_unlock_irqrestore(dev-lock, flags); 161 mod_timer(dev-timer, jiffies msecs_to_jiffies(dev-timeperiod)); 162 } 函数 timer_function定时器服务函数此函有一个参数 arg在本例程中arg 参数就是 timerdev 的地址这样通过 arg 参数就可以访问到设备结构体。当定时周期到了以后此函数就会被调用。在此函数中将 LED 灯的状态取反实现 LED 灯闪烁的效果。因为内核定时器不是循环的定时器执行一次以后就结束了因此在 161 行又调用了 mod_timer 函数重新开启定时器。 169 static int __init timer_init(void) 170 { 171 /* 初始化自旋锁 */ 172 spin_lock_init(timerdev.lock); 173 174 /* 注册字符设备驱动 */ 175 /* 1、创建设备号 */ 176 if (timerdev.major) { /* 定义了设备号 */ 177 timerdev.devid MKDEV(timerdev.major, 0); 178 register_chrdev_region(timerdev.devid, TIMER_CNT, TIMER_NAME); 179 } else { /* 没有定义设备号 */ 180 alloc_chrdev_region(timerdev.devid, 0, TIMER_CNT, TIMER_NAME); 181 timerdev.major MAJOR(timerdev.devid); /* 获取主设备号 */ 182 timerdev.minor MINOR(timerdev.devid); /* 获取次设备号 */ 183 } 184 185 /* 2、初始化 cdev */ 186 timerdev.cdev.owner THIS_MODULE; 187 cdev_init(timerdev.cdev, timer_fops); 188 189 /* 3、添加一个 cdev */ 190 cdev_add(timerdev.cdev, timerdev.devid, TIMER_CNT); 191 192 /* 4、创建类 */ 193 timerdev.class class_create(THIS_MODULE, TIMER_NAME); 194 if (IS_ERR(timerdev.class)) { 195 return PTR_ERR(timerdev.class); 196 } 197 198 /* 5、创建设备 */ 199 timerdev.device device_create(timerdev.class, NULL, timerdev.devid, NULL, TIMER_NAME); 200 if (IS_ERR(timerdev.device)) { 201 return PTR_ERR(timerdev.device); 202 } 203 204 /* 6、初始化 timer设置定时器处理函数,还未设置周期所有不会激活定时器 */ 205 init_timer(timerdev.timer); 206 timerdev.timer.function timer_function; 207 timerdev.timer.data (unsigned long)timerdev; 208 return 0; 209 } 第 169~209 行函数 timer_init驱动入口函数。在第 205~207 行初始化定时器设置定时器的定时处理函数为 timer_function另外设置要传递给 timer_function 函数的参数为 timerdev的地址。在此函数中并没有调用 timer_add 函数来开启定时器因此定时器默认是关闭的除非应用程序发送打开命令。 216 static void __exit timer_exit(void) 217 { 218 219 gpio_set_value(timerdev.led_gpio, 1); /* 卸载驱动的时候关闭 LED */ 220 del_timer_sync(timerdev.timer); /* 删除 timer */ 221 #if 0 222 del_timer(timerdev.tiemr); 223 #endif 224 225 /* 注销字符设备驱动 */ 226 cdev_del(timerdev.cdev); /* 删除 cdev */ 227 unregister_chrdev_region(timerdev.devid, TIMER_CNT); 228 229 device_destroy(timerdev.class, timerdev.devid); 230 class_destroy(timerdev.class); 231 } 驱动出口函数在 219 行关闭 LED也就是卸载驱动以后 LED 处于熄灭状态。第 220 行调用 del_timer_sync 函数删除定时器也可以使用 del_timer 函数。   3.编写测试APP 21 /* 命令值 */ 22 #define CLOSE_CMD (_IO(0XEF, 0x1)) /* 关闭定时器 */ 23 #define OPEN_CMD (_IO(0XEF, 0x2)) /* 打开定时器 */ 24 #define SETPERIOD_CMD (_IO(0XEF, 0x3)) /* 设置定时器周期命令 */ 25 26 /* 27 * description : main 主程序 28 * param - argc : argv 数组元素个数 29 * param - argv : 具体参数 30 * return : 0 成功;其他 失败 31 */ 32 int main(int argc, char *argv[]) 33 { 34 int fd, ret; 35 char *filename; 36 unsigned int cmd; 37 unsigned int arg; 38 unsigned char str[100]; 39 40 if (argc ! 2) { 41 printf(Error Usage!\r\n); 42 return -1; 43 } 44 45 filename argv[1]; 46 47 fd open(filename, O_RDWR); 48 if (fd 0) { 49 printf(Cant open file %s\r\n, filename); 50 return -1; 51 } 52 53 while (1) { 54 printf(Input CMD:); 55 ret scanf(%d, cmd); 56 if (ret ! 1) { /* 参数输入错误 */ 57 gets(str); /* 防止卡死 */ 58 } 59 60 if(cmd 1) /* 关闭 LED 灯 */ 61 cmd CLOSE_CMD; 62 else if(cmd 2) /* 打开 LED 灯 */ 63 cmd OPEN_CMD; 64 else if(cmd 3) { 65 cmd SETPERIOD_CMD; /* 设置周期值 */ 66 printf(Input Timer Period:); 67 ret scanf(%d, arg); 68 if (ret ! 1) { /* 参数输入错误 */ 69 gets(str); /* 防止卡死 */ 70 } 71 } 72 ioctl(fd, cmd, arg); /* 控制定时器的打开和关闭 */ 73 } 74 close(fd); 75 } ①、运行 APP 以后提示我们输入要测试的命令输入 1 表示关闭定时器、输入 2 表示打开定时器输入 3 设置定时器周期。 ②、如果要设置定时器周期的话需要让用户输入要设置的周期值单位为毫秒。 第 22~24 行命令值。 第 53~73 行 while(1)循环让用户输入要测试的命令然后通过第 72 行的 ioctl 函数发送给驱动程序。如果是设置定时器周期命令 SETPERIOD_CMD那么 ioctl 函数的 arg 参数就是用户输入的周期值。 四、运行测试 1.编译驱动程序和测试AP 编译成功以后就会生成一个名为“ timer.ko”的驱动模块文件。 编译成功以后就会生成 timerApp 这个应用程序。 2.运行测试 根据提示输入指令及周期观察LED的交替亮变化即可。 五、总结 本节笔记主要学习Linux内核定时器的驱动开发主要包括内核时间管理和定时器、硬件原理图分析【LED】、驱动开发和测试。最重要的内容为定时器驱动开发部分。 本文为参考正点原子开发板配套教程整理而得仅用于学习交流使用不得用于商业用途。
http://www.hkea.cn/news/14302562/

相关文章:

  • 朝阳网站搭建公司门户系统大全
  • 大人小孩做网站wordpress lazy load
  • 网站的倒计时怎么做的房地产网站大全
  • 做网站用php还是jsp手机app开发公司哪家好
  • c 企业网站开发jquery 炫酷网站
  • 用html5做的网站过程宁波cms建站
  • 高端网站制作乐是短视频营销常用的平台有
  • 网站开发 案例WordPress二级域名插件
  • 电商首页设计上海自动seo
  • 购物商城网站开发公司wordpress 相片
  • 做虚拟货币交易网站国内知名公关公司
  • 市场营销网站深圳画册设计品牌
  • DW做注册网站长沙市建设发展集团有限公司网站
  • 专门做消防器材的网站网站开发相关参考文献资料
  • 类似百科式的网站建设常州制作网站价格
  • 河北建设厅安监站官方网站网站建设套餐怎么样
  • 注册域名之后如何建设网站ssh小型购物网站开发
  • 上海虹口建设局官方网站给大家推荐免费视频服务器
  • 成都网站维护公司免费模板网站word
  • 广告设计专业技能有哪些锦州网站做优化
  • 天津滨海新区小程序网站建设html官方下载
  • 苏州网站设计营销公司凡客诚品的支付方式
  • 网站开发厂商互联网app开发
  • 云南技术网站建设销售江苏省住房保障建设厅网站
  • 做家具城网站的意义网站公司建设网站价格
  • 成都高端网站开发做搜狗网站优化排
  • 网络购物商城网站建设肇庆市网站建设平台
  • 河南省建设工程网站兰州市住房保障和城乡建设局网站
  • 南昌有哪些企业网站做网站一个月30ip
  • google如何提交网站东丽做网站