網(wǎng)站title的作用怎樣做自己的網(wǎng)站
目錄
1、項目背景
2、驅(qū)動程序
2.1 三層架構(gòu)
2.2 驅(qū)動三要素
2.3 字符設(shè)備驅(qū)動
?2.3.1 驅(qū)動模塊
2.3.2 應(yīng)用層
3、設(shè)計實現(xiàn)
3.1 項目設(shè)計
3.2 項目實現(xiàn)
3.2.1 驅(qū)動模塊代碼
3.2.2 用戶層代碼?
4、功能特性
5、技術(shù)分析?
6. 總結(jié)與未來展望
1、項目背景
? ? ? ? 養(yǎng)老院的老人在生活中難免有所不方便,為了便捷老年人的生活,使用字符設(shè)備驅(qū)動編寫了一個自助飲水機(jī)項目。該飲水機(jī)與普通飲水機(jī)的區(qū)別在于擁有更復(fù)雜的功能;飲水機(jī)擁有可以自行輸入金額,然后程序開始運(yùn)行。運(yùn)行期間常亮綠燈,可以點(diǎn)擊按鈕暫停,燈顏色改變;一直到余額不足,然后蜂鳴器提示用戶。
? ? ? ? 提示:該項目的基礎(chǔ)是在”系統(tǒng)移植“之上,對于系統(tǒng)移植步驟及說明:
????????http://t.csdnimg.cn/O1uMi
?
2、驅(qū)動程序
2.1 三層架構(gòu)

?????????對于三層的說明,想必大家都不陌生。內(nèi)核層既需要去通過轉(zhuǎn)換地址映射到內(nèi)核,使得內(nèi)核可以通過虛擬地址去操作底層的硬件設(shè)備;也需要使用虛擬文件系統(tǒng)向上層提供一個用戶能夠操作的文件設(shè)備。內(nèi)核層作為中間樞紐,能提供如此的功能,歸功于驅(qū)動程序,見圖2-2。
?
2.2 驅(qū)動三要素
//驅(qū)動模塊三要素 入口、出口、許可證
#include <linux/init.h>
#include <linux/module.h>
//入口
static int hello_init(void)
{return 0;
}
//出口
static void hello_exit(void)
{
}
module_init(hello_init);
module_exit(hello_exit);
//許可證
MODULE_LICENSE("GPL");//一個最簡單、最基本的驅(qū)動程序
?
2.3 字符設(shè)備驅(qū)動

?
?2.3.1 驅(qū)動模塊
#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/fs.h>
unsigned int major=0;
#define CNAME "hello"
ssize_t mycdev_read (struct file *file, char __user *ch, size_t len, loff_t *lodd)
{printk("this is read\n");return 0;
}
ssize_t mycdev_write (struct file *file, const char __user *buf, size_t len, loff_t *lodd)
{printk("this is write\n");return 0;
}
int mycdev_open (struct inode *ino, struct file *file)
{printk("this is open\n");return 0;
}
int mycdev_release (struct inode *ino, struct file *file)
{printk("this is close\n");return 0;
}
const struct file_operations fops=
{.read=mycdev_read,.write=mycdev_write,.open=mycdev_open,.release=mycdev_release,
};//該結(jié)構(gòu)體主要用于像上層的用戶層,提供調(diào)用的接口函數(shù)
static int __init hello_init(void)
{major=register_chrdev(major,CNAME,&fops);//注冊一個字符設(shè)備驅(qū)動if(major<0){printk("register chrdev error\n");return major;}return 0;
}
static void __exit hello_exit(void)
{unregister_chrdev(major,CNAME);printk("bai bai\n");
}
module_init(hello_init);//入口
module_exit(hello_exit);//出口
MODULE_LICENSE("GPL");//返回值
?
2.3.2 應(yīng)用層
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
char buf[128]={0};
int main(int argc,const char *argv[])
{int fd;fd=open("./hello",O_RDWR);if(fd==-1){perror("open error");return -1;}write(fd,buf,sizeof(buf));//對應(yīng)著設(shè)備驅(qū)動模塊的mycdev_write read(fd,buf,sizeof(buf));//對應(yīng)著設(shè)備驅(qū)動模塊的mycdev_readclose(fd);return 0;
}
? ? ? ? ?所以,具體應(yīng)用層所能干的,就是調(diào)用接口,而接口函數(shù)里面做的事情,則由我們驅(qū)動開發(fā)人員去編寫,當(dāng)然,此驅(qū)動模塊還沒有去操作實際的硬件設(shè)備,對于想要操作底層的硬件設(shè)備,則需要去看板子的原理圖,查看外設(shè)的地址映射等。(以上驅(qū)動模塊并未自動創(chuàng)建設(shè)備文件,執(zhí)行完還需自行mknod,命令格式如下:sudo mknod hello c/b(c 代表字符設(shè)備 b代表塊設(shè)備)主設(shè)備號 次設(shè)備號)
3、設(shè)計實現(xiàn)
3.1 項目設(shè)計
? ? ? ? 對于該項目組成,同樣是上述組成,不過更加復(fù)雜,具體的我就不再引出了。如果有任何問題,可以聯(lián)系博主。

3.2 項目實現(xiàn)
3.2.1 驅(qū)動模塊代碼
#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>#define CNAME "NEW_C"
unsigned int major=0;
struct class *cls;
struct device *dvs;
char kbuf[64]={0};
int money=0;
int devlen=0;#define RED_BASE 0xC001A000
#define GRE_BASE 0xC001E000
#define BLU_BASE 0xC001B000
#define BEEP_BASE 0xC001C000
unsigned int *red_base=NULL;
unsigned int *gre_base=NULL;
unsigned int *blu_base=NULL;
unsigned int *beep_base=NULL;#define GPIONO(m,n) m*32+n //計算gpio號
#define GPIO_B8 (GPIONO(1,8))//計算按鍵gpio號
#define GPIO_B16 (GPIONO(1,16)) //計算gpio號
struct timer_list mytimer;//聲明結(jié)構(gòu)體
struct timer_list mytimer1;
struct timer_list mytimer2;
int gpiono[] = {GPIO_B8,GPIO_B16};//數(shù)組內(nèi)存入兩個按鍵的軟中斷號
char *irqname[] = {"interrupt-b8","interrupt-b16"};//中斷的名字
void key_irq_timer_handle(unsigned long data)//定時器中斷處理函數(shù)
{int status_b8 = gpio_get_value(GPIO_B8);//讀取gpiob8數(shù)值int status_b16 = gpio_get_value(GPIO_B16);//讀取gpiob16數(shù)值if(status_b8 == 0){//如果等于0表示按下,執(zhí)行打印函數(shù)*blu_base |= 1<<12;mod_timer(&mytimer1,jiffies+1000);printk("left button down............\n");}if(status_b16 == 0){//如果等于0表示按下,執(zhí)行打印函數(shù)*blu_base &= ~(1<<12);del_timer(&mytimer1);printk("right button down#############\n");}
}void key_irq_timer_handle1(unsigned long data)//定時器中斷處理函數(shù)
{kbuf[11]=kbuf[11]-1;if(kbuf[11]=='/'){kbuf[10]=kbuf[10]-1;kbuf[11]=kbuf[11]+10;}mod_timer(&mytimer1, jiffies + 1000);
}void key_irq_timer_handle2(unsigned long data)//定時器中斷處理函數(shù)
{*beep_base &= ~(1<<14);
}
irqreturn_t farsight_irq_handle(int num, void *dev)//按鍵產(chǎn)生的中斷處理函數(shù)
{mod_timer(&mytimer,jiffies+10);//開啟定時器。只要觸發(fā)就重新賦值,用來消抖return IRQ_HANDLED;
}ssize_t my_dev_read(struct file *file, char __user *ubuf, size_t len, loff_t *loff)
{if(len >sizeof(kbuf)){len =sizeof(kbuf);}printk("%c %c\n",kbuf[10],kbuf[11]);devlen = copy_to_user(ubuf,kbuf,len);if(devlen){printk("copy to user is err\n");return devlen;}return 0;
}ssize_t my_dev_write(struct file *file, const char __user *ubuf, size_t len, loff_t *loff)
{if(len > sizeof (kbuf)){len=sizeof(kbuf);}devlen = copy_from_user(kbuf,ubuf,len);if(devlen){printk("copy from user is err\n");return devlen;}money=(kbuf[10]-48)*10+(kbuf[11]-48);printk("This is my char_dev_write %d\n",money);return 0;
}int my_dev_open(struct inode *inode, struct file *file)
{return 0;
}int my_dev_release(struct inode *inode, struct file *file)
{*beep_base |= 1<<14;mod_timer(&mytimer2, jiffies + 1000);return 0;
}const struct file_operations fops=
{.read=my_dev_read,.write=my_dev_write,.open=my_dev_open,.release=my_dev_release,// .unlocked_ioctl=my_unlocked_ioctl,
};static int __init hello_init(void)
{major=register_chrdev(major,CNAME,&fops);if(major<0){printk("register_chrdev is error\n");return major;}red_base=ioremap(RED_BASE,36);gre_base=ioremap(GRE_BASE,36);blu_base=ioremap(BLU_BASE,36);beep_base=ioremap(BEEP_BASE,36);if(red_base==NULL || gre_base==NULL){printk("ioremap is err\n");return -ENOMEM;}*red_base &=~(1<<28);*(red_base+1) |=1<<28;*(red_base+9) &=~(3<<24);*gre_base &= ~(1<<13);*(gre_base+1) |= (1<<13);*(gre_base+8) &=~(3<<26);*(blu_base+1) |= 1<<12;*(blu_base+8) |=(2<<24);*beep_base &= ~(1<<14);*(beep_base+1) |= 1<<14;*(beep_base+8) &= ~(1<<29);*(beep_base+8) |= 1<<28;cls = class_create(THIS_MODULE, CNAME);if(IS_ERR(cls)){printk("class create is err\n");return PTR_ERR(cls);}dvs=device_create(cls, NULL, MKDEV(major,0), NULL, CNAME);if(IS_ERR(dvs)){printk("device create is err\n");return PTR_ERR(dvs);}int ret,i;mytimer.expires = jiffies + 10;//時間mytimer.function = key_irq_timer_handle;//定時器中斷處理函數(shù)mytimer.data = 0;//參數(shù)init_timer(&mytimer);//將定時器信息寫入進(jìn)行初始化add_timer(&mytimer);//開啟一次定時器mytimer1.expires = jiffies + 1000;//時間mytimer1.function = key_irq_timer_handle1;//定時器中斷處理函數(shù)mytimer1.data = 0;//參數(shù)init_timer(&mytimer1);//將定時器信息寫入進(jìn)行初始化add_timer(&mytimer1);//開啟一次定時器mytimer2.expires = jiffies + 1000;//時間mytimer2.function = key_irq_timer_handle2;//定時器中斷處理函數(shù)mytimer2.data = 0;//參數(shù)init_timer(&mytimer2);//將定時器信息寫入進(jìn)行初始化add_timer(&mytimer2);//開啟一次定時器for(i=0;i<ARRAY_SIZE(gpiono); i++){//這里用for主要目的之申請兩個中斷ret = request_irq(gpio_to_irq(gpiono[i]),farsight_irq_handle,IRQF_TRIGGER_FALLING,irqname[i],NULL);//中斷申請 參數(shù):軟中斷號 中斷執(zhí)行函數(shù) 下降沿觸發(fā) 中斷的名字if(ret){printk("request irq%d error\n",gpio_to_irq(gpiono[i]));//申請失敗提示return ret;}}return 0;
}static void __exit hello_exit(void)
{int i;for(i=0;i<ARRAY_SIZE(gpiono); i++){//注銷掉中斷free_irq(gpio_to_irq(gpiono[i]),NULL);}del_timer(&mytimer);//注銷掉定時器del_timer(&mytimer1);//注銷掉定時器del_timer(&mytimer2);//注銷掉定時器class_destroy(cls);device_destroy(cls,MKDEV(major,0));iounmap(red_base);iounmap(gre_base);iounmap(blu_base);iounmap(beep_base);unregister_chrdev(major,CNAME);}module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
3.2.2 用戶層代碼?
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <time.h>#include "head.h"char buf[64] ={0};
char buff[128]={0};
struct tm *tp;
time_t t;
int main(int argc, char *argv[])
{int fd = open("/dev/NEW_C", O_RDWR);if (fd < 0){perror("open NEW_C err\n");return -1;}int fds=open("./history.txt",O_APPEND|O_CREAT|O_WRONLY,0666);if(fds<0){perror("open history err\n");return -1;}sprintf(buf,"0X55%s%s0XFF",argv[1],argv[2]);write(fd,buf,sizeof(buf));int readlen=0;while(1){time(&t);tp = localtime(&t);if((buf[10]=='0') && buf[11]=='0'){goto loop;}readlen = read(fd,buf,sizeof(buf));sprintf(buff,"%4d-%02d-%02d %02d:%02d:%02d : 賬戶:%c%c\t剩余金額:%c%c\n",tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday,tp->tm_hour,tp->tm_min,tp->tm_sec,buf[6],buf[7],buf[10],buf[11]);write(fds,buff,strlen(buff));printf("賬戶:%c%c\t剩余金額:%c%c\n",buf[6],buf[7],buf[10],buf[11]);sleep(1);}
loop:close(fd);return 0;
}
?
4、功能特性
上述項目的功能大體如下:
? ? ? ? 用戶可自行輸入金額。
? ? ? ? 金額定時減少,出水時亮綠燈
? ? ? ? 用戶可點(diǎn)擊按鈕實現(xiàn)暫停接水,并且余額不會減少。
? ? ? ? 余額歸零,代表出水完畢,蜂鳴器響提示用戶。
? ? ? ? 本地日志會記錄用戶的購買記錄及詳細(xì)信息。
?
5、技術(shù)分析?
? ? ? ? 字符設(shè)備驅(qū)動編寫:向上提供接口,向下控制硬件。
? ? ? ? 定時器使用:按鍵消抖,水量控制,蜂鳴器控制。
? ? ? ? 中斷使用:按鍵觸發(fā)中斷。
? ? ? ? 文件io:保存用戶消費(fèi)日志。
?
6. 總結(jié)與未來展望
? ? ? ??字符設(shè)備驅(qū)動是操作系統(tǒng)中的一種設(shè)備驅(qū)動程序,用于管理和控制字符設(shè)備。在Linux系統(tǒng)中,字符設(shè)備驅(qū)動通常使用字符設(shè)備接口進(jìn)行開發(fā)。驅(qū)動程序需要定義設(shè)備結(jié)構(gòu)體、注冊設(shè)備、實現(xiàn)文件操作函數(shù)等,以提供穩(wěn)定高效的設(shè)備訪問接口。除了基本的功能,驅(qū)動程序還可以實現(xiàn)多個進(jìn)程訪問同一個設(shè)備、內(nèi)存映射、虛擬文件系統(tǒng)、設(shè)備驅(qū)動模塊化、調(diào)試信息輸出等特性。
????????字符設(shè)備驅(qū)動技術(shù)在計算機(jī)領(lǐng)域有著重要的意義和影響。首先,它為應(yīng)用程序提供了訪問字符設(shè)備的標(biāo)準(zhǔn)接口,使得應(yīng)用程序能夠方便地與設(shè)備進(jìn)行數(shù)據(jù)交互,從而促進(jìn)了各種應(yīng)用軟件的開發(fā)和推廣。其次,字符設(shè)備驅(qū)動技術(shù)也支持多種設(shè)備類型和多種操作系統(tǒng)平臺,使得設(shè)備之間的互通性得到了提升,為設(shè)備互聯(lián)和智能化提供了先決條件。
????????未來,隨著物聯(lián)網(wǎng)技術(shù)的不斷發(fā)展和普及,字符設(shè)備驅(qū)動技術(shù)將會得到更廣泛的應(yīng)用和推廣。特別是在智能家居、工業(yè)自動化、醫(yī)療健康等領(lǐng)域,字符設(shè)備驅(qū)動技術(shù)將發(fā)揮更大的作用和貢獻(xiàn)。同時,隨著技術(shù)的不斷進(jìn)步和創(chuàng)新,字符設(shè)備驅(qū)動技術(shù)也將會不斷完善和優(yōu)化,以滿足日益增長的設(shè)備互聯(lián)需求和應(yīng)用場景。
? ? ? ? 感謝大家的閱讀,歡迎留言指教。