驅動DAY5

1.實現設備文件和設備的綁定,編寫LED驅動

2.復習競態的解決方法和阻塞IO實現

第一個任務

頭文件

#ifndef __HEAD_H__
#define __HEAD_H__ 
typedef struct{unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR;
}gpio_t;#define PHY_LED1_ADDR 0X50006000
#define PHY_LED2_ADDR 0X50007000
#define PHY_LED3_ADDR 0X50006000
#define PHY_RCC_ADDR  0X50000A28#define LED_ON _IO('l',1)//開燈
#define LED_OFF _IO('l',0)//關燈#endif 

驅動代碼

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include "head.h"
#include <linux/slab.h>
#include <linux/io.h>struct cdev *cdev;
unsigned int major = 0;
unsigned int minor = 0;
dev_t devno;
struct class *cls;
struct device *dev;char kbuf[128] = {0};
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;// 定義互斥體
struct mutex mutex;// 封裝操作方法
int mycdev_open(struct inode *inode, struct file *file)
{// 上鎖mutex_lock(&mutex);unsigned int minor = MINOR(inode->i_rdev); // 獲取操作的文件的次設備號file->private_data = (void *)minor;        // 將次設備當作file對象的私有數據存放printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{unsigned int which = (unsigned int)file->private_data; // 獲取到open中得到的文件的次設備號switch (which)                                         // 根據次設備號的不同控制不同的LED燈{case 0: // LED1控制switch (cmd){case LED_ON:// LED1開燈vir_led1->ODR |= (0X1 << 10);break;case LED_OFF:// LED1關燈vir_led1->ODR &= (~(0X1 << 10));break;}break;case 1: // LED2控制switch (cmd){case LED_ON:// LED2開燈vir_led2->ODR |= (0X1 << 10);break;case LED_OFF:// LED2關燈vir_led2->ODR &= (~(0X1 << 10));break;}break;case 2: // LED3switch (cmd){case LED_ON:// LED3開燈vir_led3->ODR |= (0X1 << 8);break;case LED_OFF:// LED3關燈vir_led3->ODR &= (~(0X1 << 8));break;}break;default:printk("驅動程序 燈選擇錯誤\n");break;}/*// 根據用戶空間功能碼的不同實現硬件不同的控制switch (cmd){case LED_ON: // 開燈switch (arg){case 1:vir_led1->ODR |= (0X1 << 10);break;case 2:vir_led2->ODR |= (0X1 << 10);break;case 3:vir_led3->ODR |= (0X1 << 8);break;default:printk("燈選擇輸入錯誤\n");break;}break;case LED_OFF: // 關燈switch (arg){case 1:vir_led1->ODR &= (~(0X1 << 10));break;case 2:vir_led2->ODR &= (~(0X1 << 10));break;case 3:vir_led3->ODR &= (~(0X1 << 8));break;default:printk("燈選擇輸入錯誤\n");break;}break;default:printk("開關燈選擇輸入錯誤\n");break;}*/return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{// 解鎖mutex_unlock(&mutex);printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
// 定義操作方法結構體遍歷并且初始化
struct file_operations fops = {.open = mycdev_open,.unlocked_ioctl = mycdev_ioctl,.release = mycdev_close,
};int all_led_init(void)
{// 寄存器地址的映射vir_led1 = ioremap(PHY_LED1_ADDR, sizeof(gpio_t));if (vir_led1 == NULL){printk("ioremap filed:%d\n", __LINE__);return -ENOMEM;}vir_led2 = ioremap(PHY_LED2_ADDR, sizeof(gpio_t));if (vir_led2 == NULL){printk("ioremap filed:%d\n", __LINE__);return -ENOMEM;}vir_led3 = vir_led1;vir_rcc = ioremap(PHY_RCC_ADDR, 4);if (vir_rcc == NULL){printk("ioremap filed:%d\n", __LINE__);return -ENOMEM;}printk("物理地址映射成功\n");// 寄存器的初始化// rcc(*vir_rcc) |= (3 << 4);// led1vir_led1->MODER &= (~(3 << 20));vir_led1->MODER |= (1 << 20);vir_led1->ODR &= (~(1 << 10));// led2vir_led2->MODER &= (~(3 << 20));vir_led2->MODER |= (1 << 20);vir_led2->ODR &= (~(1 << 10));// led3vir_led3->MODER &= (~(3 << 16));vir_led1->MODER |= (1 << 16);vir_led1->ODR &= (~(1 << 8));printk("寄存器初始化成功\n");return 0;
}static int __init mycdev_init(void)
{// 初始化互斥體mutex_init(&mutex);int ret;// 1.分配字符設備驅動對象cdev = cdev_alloc();if (cdev == NULL){printk("申請字符設備驅動對象失敗\n");ret = -EFAULT;goto OUT1;}printk("申請字符設備驅動成功\n");// 2.初始化字符設備驅動對象cdev_init(cdev, &fops);// 3.申請設備號if (major > 0) // 靜態指定{ret = register_chrdev_region(MKDEV(major, minor), 3, "mycdev");if (ret){printk("靜態指定設備號失敗\n");goto OUT2;}}else{ret = alloc_chrdev_region(&devno, minor, 3, "mycdev");if (ret){printk("靜態指定設備號失敗\n");goto OUT2;}minor = MINOR(devno); // 根據設備號獲取次設備號major = MAJOR(devno); // 根據設備號獲取主設備號}printk("申請設備號成功\n");// 4.注冊字符設備驅動對象ret = cdev_add(cdev, MKDEV(major, minor), 3);if (ret){printk("注冊字符設備驅動對象失敗\n");goto OUT3;}printk("注冊字符設備驅動對象成功\n");// 向上提交目錄cls = class_create(THIS_MODULE, "mycdev");if (IS_ERR(cls)){printk("向上提交目錄失敗\n");ret = -PTR_ERR(cls);goto OUT4;}printk("向上提交目錄成功\n");// 向上提交設備節點信息int i = 0;for (i = 0; i < 3; i++){dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mycdev%d", i);if (IS_ERR(dev)){printk("向上提交設備節點信息失敗\n");ret = -PTR_ERR(dev);goto OUT5;}}printk("向上提交設備節點成功\n");// 寄存器映射以及初始化all_led_init();return 0;
OUT5:for (--i; i >= 0; i--){device_destroy(cls, MKDEV(major, i)); // 釋放提交成功的設備信息}class_destroy(cls); // 銷毀目錄
OUT4:cdev_del(cdev);
OUT3:unregister_chrdev_region(MKDEV(major, minor), 3);
OUT2:kfree(cdev);
OUT1:return ret;
}
static void __exit mycdev_exit(void)
{// 銷毀設備節點信息int i;for (i = 0; i < 3; i++){device_destroy(cls, MKDEV(major, i));}// 銷毀目錄class_destroy(cls);// 注銷字符設備驅動對象cdev_del(cdev);// 釋放設備號unregister_chrdev_region(MKDEV(major, minor), 3);// 釋放對象空間kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

LED1測試代碼

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include "head.h"int main(int argc, char const *argv[])
{char buf[128] = {0};int a, b;int fd = open("/dev/mycdev0", O_RDWR);if (fd < 0){printf("打開設備文件失敗\n");exit(-1);}while (1){printf("LED1設置 請輸入要實現的功能: 1 ( 開燈 ) 0 ( 關燈> )  9 退出");scanf("%d", &a);/*printf("請輸入要控制的燈:1(LED1) 2(LED2) 3(LED3)>");scanf("%d", &b);*/switch (a){case 1:ioctl(fd, LED_ON);break;case 0:ioctl(fd, LED_OFF);break;case 9:return -1;default:printf("LED1測試代碼  開關燈選擇輸入錯誤\n");break;}}close(fd);return 0;
}

LED2測試代碼

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include "head.h"int main(int argc, char const *argv[])
{char buf[128] = {0};int a, b;int fd = open("/dev/mycdev1", O_RDWR);if (fd < 0){printf("打開設備文件失敗\n");exit(-1);}while (1){printf("LED2設置 請輸入要實現的功能: 1 ( 開燈 ) 0 ( 關燈> )  9 退出");scanf("%d", &a);/*printf("請輸入要控制的燈:1(LED1) 2(LED2) 3(LED3)>");scanf("%d", &b);*/switch (a){case 1:ioctl(fd, LED_ON);break;case 0:ioctl(fd, LED_OFF);break;case 9:return -1;default:printf("LED2測試代碼  開關燈選擇輸入錯誤\n");break;}}close(fd);return 0;
}

LED3測試代碼

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include "head.h"int main(int argc, char const *argv[])
{char buf[128] = {0};int a, b;int fd = open("/dev/mycdev2", O_RDWR);if (fd < 0){printf("打開設備文件失敗\n");exit(-1);}while (1){printf("LED3設置 請輸入要實現的功能: 1 ( 開燈 ) 0 ( 關燈> ) 9 退出");scanf("%d", &a);/*printf("請輸入要控制的燈:1(LED1) 2(LED2) 3(LED3)>");scanf("%d", &b);*/switch (a){case 1:ioctl(fd, LED_ON);break;case 0:ioctl(fd, LED_OFF);break;case 9:return -1;default:printf("LED3測試代碼  開關燈選擇輸入錯誤\n");break;}}close(fd);return 0;
}

串口工具現象

開發板現象

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/42223.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/42223.shtml
英文地址,請注明出處:http://en.pswp.cn/news/42223.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【MySQL系列】表內容的基本操作(增刪查改)

「前言」文章內容大致是對MySQL表內容的基本操作&#xff0c;即增刪查改。 「歸屬專欄」MySQL 「主頁鏈接」個人主頁 「筆者」楓葉先生(fy) 目錄 一、MySQL表內容的增刪查改1.1 Create1.1.1 單行數據全列插入1.1.2 多行數據指定列插入1.1.3 插入否則更新1.1.4 數據替換 1.2 Ret…

MS Word表格寬度自適應

x.1 問題&#xff1a; 你的表格可能并沒有占滿整行&#xff0c;且右對齊&#xff0c;例如如下&#xff0c; x.2 解決方式 這個時候你想右對齊&#xff0c;你可以這么操作&#xff0c;點左上角的十字全選表格&#xff0c; 在布局里選擇自動對齊&#xff0c; 對齊方式選擇居中右…

git日常操作-案例

文章目錄 查看tag對應版本tag一個版本切換到指定tag查看遠程有那些分支 查看tag對應版本 要查看 Git 倉庫中標簽&#xff08;tag&#xff09;對應的版本&#xff0c;可以使用以下命令&#xff1a; git show <tag>將 替換為你要查看的標簽名稱。該命令將顯示與標簽對應的…

springBoot是如何實現自動裝配的

目錄 1 什么是自動裝配 2 Spring自動裝配原理 2.1 SpringBootConfiguration ?編輯 2.2 EnableAutoConfiguration 2.2.1 AutoConfigurationPackage 2.2.2 Import({AutoConfigurationImportSelector.class}) 2.3 ComponentScan 1 什么是自動裝配 自動裝配就是將官方寫好的的…

vue-cli前端工程化——創建vue-cli工程 router版本的創建 目錄結構 案例初步

目錄 引出創建vue-cli前端工程vue-cli是什么自動構建創建vue-cli項目選擇Vue的版本號 手動安裝進行選擇創建成功 手動創建router版多了一個router 運行測試bug解決 Vue項目結構main.jspackage.jsonvue.config.js Vue項目初步hello案例 總結 引出 1.vue-cli是啥&#xff0c;創建…

Redis Geo 數據類型在移動互聯網中的應用

Redis Geo 數據類型在移動互聯網中的應用 一、簡介1 Redis2 數據類型 二、Geo 數據類型1 Geo 數據類型2 Geo 數據類型的存儲方式3 Geo 數據類型的常用命令 三、Geo 數據類型應用場景1 附近的人和地點功能2 出租車實時定位3 物流配送服務 四、Redis Geo 數據優化策略1 降低查詢延…

android手勢事件

與手勢事件有關的方法 dispatchTouchEvent()&#xff1a;該方法將觸摸事件分發給相應的視圖或視圖組。onInterceptTouchEvent()&#xff1a;該方法用于判斷是否需要攔截觸摸事件&#xff0c;如果需要攔截&#xff0c;則返回 true&#xff0c;否則返回 false。onTouchEvent()&a…

神經網絡基礎-神經網絡補充概念-36-dropout正則化

概念 Dropout 是一種常用的正則化技術&#xff0c;用于減少深度神經網絡中的過擬合問題。它在訓練過程中隨機地將一部分神經元的輸出置為零&#xff0c;從而強制模型在訓練過程中學習多個獨立的子模型&#xff0c;從而減少神經元之間的依賴關系&#xff0c;提高模型的泛化能力…

記一次項目內存優化--內存泄漏

需求–內存泄漏優化&#xff0c;PSS有所下降&#xff0c; OOM率減少 主要是與某個版本作基準進行對比&#xff08;一般是最新版本的前一個版本作原數據&#xff09;&#xff0c;優化后&#xff0c;PSS有所下降&#xff0c;線上OOM率減少&#xff08;Bugly版本對比&#xff09;…

程序員如何利用公網遠程訪問查詢本地硬盤【內網穿透】

&#x1f3ac; 鴿芷咕&#xff1a;個人主頁 &#x1f525; 個人專欄: 《高效編程技巧》《cpolar》 ??生活的理想&#xff0c;就是為了理想的生活! 公網遠程訪問本地硬盤文件【內網穿透】 文章目錄 公網遠程訪問本地硬盤文件【內網穿透】前言1. 下載cpolar和Everything軟件1.…

React 生態應用 - React Router(1)

目錄 擴展學習資料 安裝和導入 Route匹配 src/components/navbar.jsx src/App.js 擴展學習資料 資料名稱 鏈接 備注 閱讀react router組件文檔 https://react-router.docschina.org/web/guides/philosophy Introduction | React Router 中文文檔 擴展閱讀 路由鑒權 …

(stm32)低功耗模式

低功耗模式 執行哪個低功耗模式的程序判斷流程 標志位設置操作一定要在WFI/WFE之前&#xff0c;調用此指令后立即進入睡眠判斷流程 模式對比 睡眠模式 停止模式 待機模式

FLatten Transformer

FLatten Transformer: Vision Transformer using Focused Linear Attention ICCV 2023 聚焦式線性注意力模塊 關于Transformer 在Transformer模型應用于視覺領域的過程中&#xff0c;降低自注意力的計算復雜度是一個重要的研究方向。線性注意力通過兩個獨立的映射函數來近似S…

3 Python的數據類型

概述 在上一節&#xff0c;我們介紹了Python的基礎語法&#xff0c;包括&#xff1a;編碼格式、標識符、關鍵字、注釋、多行、空行、縮進、引號、輸入輸出、import、運算符、條件控制、循環等內容。Python是一種動態類型的編程語言&#xff0c;這意味著當你創建一個變量時&…

1.初識Web

文章目錄 1. 什么是Web?2.初始Web前端2.1.Web標準 1. 什么是Web? web:全球廣域網&#xff0c;也稱萬維網(www World Wide Web)&#xff0c;能夠通過瀏覽器訪問的網站。 2.初始Web前端 網頁有哪些部分組成&#xff1f; 文字、圖片、音頻、視頻、超鏈接… 我們看到的網頁&am…

react 生命周期方法

組件的生命周期 每個組件都包含 “生命周期方法”&#xff0c;你可以重寫這些方法&#xff0c;以便于在運行過程中特定的階段執行這些方法。你可以使用此生命周期圖譜作為速查表。在下述列表中&#xff0c;常用的生命周期方法會被加粗。其余生命周期函數的使用則相對罕見。 掛…

Windows Oracle21C與PLSQL Developer 15配置

1、下載Oracle21c并安裝 下載地址&#xff1a;https://www.oracle.com/database/technologies/oracle21c-windows-downloads.html 2、下載PLSQL Developer 15并安裝 下載地址&#xff1a;https://www.allroundautomations.com/products/pl-sql-developer/#pricing 3、配置O…

TypeScript教程(四)基本運算符

一、運算符 TypeScript包含以下幾種運算符&#xff1a; 1.算術運算符 2.邏輯運算符 3.關系運算符 4.按位運算符 5.賦值運算符 6.三元/條件運算符 7.字符串運算符 8.類型運算符 1.算術運算符 y5 運算符描述例子x 運算結果y 運算結果加法xy275-減法xy-235*乘法xy*2105…

在線課堂錄播直播管理系統SpringBoot+Vue

在線課堂錄播直播管理系統SpringBootVue 文章目錄 在線課堂錄播直播管理系統SpringBootVue共三個端&#xff1a;后端、后臺管理系統、前端&#xff0c;如要學習看評論區&#xff08;全部源碼、文檔、數據庫&#xff09;。內置功能一、前端二、后臺管理三、后端--代碼全有。四、…

數據結構—排序

8.排序 8.1排序的概念 什么是排序&#xff1f; 排序&#xff1a;將一組雜亂無章的數據按一定規律順序排列起來。即&#xff0c;將無序序列排成一個有序序列&#xff08;由小到大或由大到小&#xff09;的運算。 如果參加排序的數據結點包含多個數據域&#xff0c;那么排序往…