实验三 嵌入式Linux驱动(1)

更新时间:2023-03-08 08:53:35 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

实验三嵌入式Linux驱动(1)

一、 【实验目的】

1) 熟悉嵌入式Linux驱动程序编写框架。

2) 了解七段数码管驱动程序的工作原理,熟练掌握该驱动程序在嵌入式开

发平台的移植和注册使用。

二、 【实验内容】

1) 学习Linux驱动源代码,分析代码中各个函数模块的功能作用。 2) 在宿主机上交叉编译七段数码管驱动程序,然后移植到目标机上。 3) 在目标机上注册驱动程序,验证驱动的功能。

三、 【实验步骤】

1. 了解七段数码管工作原理

七段数码管是显示数字的电子元件,因为借助七个发光二极管以不同组合来显示数字,所以称为七段数码管(如图1)。七段数码管分为共阴极和共阳极,共阳极的七段数码管的正极(或者阳极)为八个发光二极管的共有正极,其他接点为独立发光二极管的负极(或者阴极),使用者只需要把正极接电,不同的负极接地就可以控制七段数码管显示不同的数字。共阴极的七段数码管与共阳极的只是接电的接法相反而已。

图1

2. 开发板七段数码管电路介绍

开发板上有四个七段共阴数码管,2个一组,第一组七段数码管使用系统LED_CS2作为其位选使能信号,两个数码管的段选信号分别使用数据总线的D0~D7位和D8~D15位,如图2所示。

图2

第二组七段数码管使用系统LED_CS3作为其位选使能信号,两个数码管的段选信号分别使用数据总线的D0~D7位和D8~D15位,如图3所示。

图3

分析可知,对七段数码管的操作主要是对其位选和段选信号的控制。其 中位选信号决定显示哪个七段数码管,段选信号决定其显示的字型信息(共阴极七段数码管段选控制信息如表1),这也是驱动程序和硬件关联的主要部分。 字型 0 1 2 3 4 5 6 7 8 9 A B C D

D7 Dp 0 0 0 0 0 0 0 0 0 0 0 0 0 0 D6 G 1 0 1 1 1 1 1 0 1 1 1 1 0 1 D5 F 1 0 0 0 1 1 1 0 1 1 1 1 1 0 D4 E 1 0 1 0 0 0 1 0 1 0 1 1 1 1 D3 D 1 0 1 1 0 1 1 0 1 1 0 1 1 1 D2 C 1 1 0 1 1 1 1 1 1 1 1 1 0 1 D1 B 1 1 1 1 1 0 0 1 1 1 1 0 0 1 D0 A 1 0 1 1 0 1 1 1 1 1 1 0 1 0 编码 0X3F 0X06 0X5B 0X4F 0X66 0X6D 0X7D 0X07 0X7F 0X6F 0X77 0X7C 0X39 0X5E

E F 0 0 1 1 1 1 1 1 表1

1 0 0 0 0 0 1 1 0X79 0X71 3. 七段数码管驱动程序分析

1) 添加驱动程序所需的头文件和变量:SEG_CS1和SEG_CS2就是上面硬

件接口所提及的两组七段数码管的位选使能信号,LED[10]数组中保存的就是在共阴极数码管上面显示0~9的段选信号。Seg这个结构体用于保存4个数码管即时显示的数字的段选信号。

#include #include #include

#include #include

MODULE_LICENSE(\//用于声明描述内核模块的许可权限,如果不声明LICENSE,模块被加载时将收到内核被污染(kernel tainted)的警告 char LED_MODULE=0;

#define DEVICE_NAME \#define SEG_CS1 0x10300000 #define SEG_CS2 0x10400000

static char LED[10]={0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7F, 0x6F}; unsigned long *CS1_Address, *CS2_Address; structseg { char LED1_Val; char LED2_Val; char LED3_Val; char LED4_Val; char negative; };

2) 同时更新所有七段数码管驱动显示函数:CS1_address对应第一组七段数

码管的位选信号,该组第一个数码管的段选信号保存在short变量的低8位,该组第二个数码管的段选信号保存在short变量的高8位。CS2_address对应第二组七段数码管,其余操作和第一组的七段数码管一

致。

static void Updateled(struct seg *seg_7) { unsigned short buff=0x00; buff=seg_7->LED1_Val; buff=buff|( seg_7->LED2_Val <<8); writew(buff,CS1_Address); buff=0x00; buff=seg_7->LED3_Val; buff=buff|( seg_7->LED4_Val<<8); writew(buff,CS2_Address); return; }

3) 写具体某位七段数码光驱动管显示函数:position对应的是4个七段数码

管的相对位置,value就是需要更新的七段数码管要显示数字的段选信号值。

voidvalue_seting(struct seg *seg_7, char position, char value) { if (seg_7->negative==0) value=~value & ~(0x1<<7); else value=(0x1<<7)|value; if (position==1) seg_7->LED1_Val=value; else if(position==2) seg_7->LED2_Val=value; else if(position==3) seg_7->LED3_Val=value; else if(position==4) seg_7->LED4_Val=value; }

4) 实现七段数码管驱动写操作函数:把用户写入的数码管显示更新数据,

转换成为要显示数字对应的段选信号,并且保存在led_forall数组中,并且调用Value_setting更新显示数据,最后调用Updateled()更新实际的数码管显示信息。

staticssize_t seg7_write(struct file *file, const char *buffer, size_t count, loff_t *

printf(\ [3] All Display\\n\ printf(\ [4] Clear Display\\n\ printf(\ [5] Write Display\\n\ printf(\ [C] Close Device\\n\ printf(\ [x] Exit Test\\n\ printf(\ ***********************\\n\ printf(\ }

int main(intargc, char **argv) { intfd=-1; intnum=0; charch=0x00; unsigned char led[4]; display_menu(); while(1) {

ch=getchar();

switch(ch) { case '0': if(fd>0) { printf(\ } else { fd = open(SEG_DEV, O_RDWR); if(fd< 0) printf(\ else printf(\ } display_menu(); break; case '1': if(fd>0) { appear_same(fd); clear_led(fd); }

else

printf(\ display_menu(); break; case '2': if(fd>0) { appear_roll(fd); clear_led(fd); } else

printf(\display_menu(); break; case '3': if(fd>0) display_led(fd); else printf(\display_menu(); break; case '4': if(fd>0) clear_led(fd); else printf(\display_menu(); break; case '5': if(fd>0) { printf(“please input a number(0 <= number <=9999):”); scanf(“%d”, &num); if (num<0 || num> 9999) printf(“can not display this number.\\n”); else { led[0]=num/1000; led[1]=(num00)/100; led[2]=(num0)/10; led[3]=num; write(fd,led,4); } } else

printf(\display_menu(); break; case 'c': case 'C': if(fd>0) { clear_led(fd); sleep(1); close(fd); printf(\ fd=-1; } display_menu(); break; case 'x': case 'X': if(fd>0) { clear_led(fd); sleep(1); close(fd); } exit(0); break; } } return(0); }

2) 测试程序的Makefile文件内容: seg7_test:seg7_test.c arm-linux-gcc seg7_test.c -o seg7_test clean: rm -f seg7_test

5. 七段数码管驱动的交叉编译

1) 进入目录/root/Backup/source下,解压缩驱动源代码到指定路径。

图4

2) 交叉编译驱动:进入/root/Backup/Driver/xidian_seg7目录下,编译源程序。

图5

3) 在确认测试代码和Makefile文件编写无误之后,交叉编译测试代码。

图6

4) 调用file命令查看文件格式,编译出来的可执行程序seg7_test是ARM

的ELF文件。

图7

6. 驱动程序的移植、注册与测试

1) 首先确认实验板和主机的网络连通,然后调用scp命令将测试程序和驱

动程序模块拷贝到目标机上(目标机root用户的密码为“xidian”)。

图8

拷贝成功后,驱动和测试程序保存在目标机的/opt目录下面,如图9所示:

图9

2) 在目标机上利用mknod命令建立设备文件节点;并利用insmod命令动

态加载驱动模块,同时利用lsmod命令查看驱动模块的加载情况。

图10

执行完以上三条命令后,驱动模块成功添加进内核中,完成注册。 3) 在目标机的/opt目录下执行驱动测试程序。

图11

首先在实验板终端驱动测试程序中输入0,打开设备,如果设备成功打开,会在终端打印出提示信息如图12所示。

图12

然后依次调用选项1,2,3,4等,观察实验板上七段数码管执行的结果,分析之前的驱动测试程序各个函数模块的功能,最后在测试程序执行完毕之后,键入dmesg命令,查看驱动测试程序在测试和加载中的输出信息(如图13所示),分析驱动代码,加深对其的理解。

图13

4) 4)卸载驱动程序,删除设备文件。

图14

本文来源:https://www.bwwdw.com/article/a9h3.html

Top