




已阅读5页,还剩21页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
沈阳理工大学课程设计专用纸 目录第一章 引言- 1 -第二章 设计目的- 2 -第三章 设计原理- 3 -第四章 关键技术- 4 -4.1 ARM9处理器- 4 -4.2嵌入式C语言开发技术- 4 -4.3 ADS开发环境- 5 -4.4基于ARM9的硬件- 6 -第五章 程序流程- 7 -5.1初始化和结束程序- 7 -5.2服务于I/O请求的函数- 7 -5.3中断服务程序- 9 -第六章 主要源代码- 10 -6.1定义与A/D转换相关的寄存器- 10 -6.2对A/D转换器进行初始化- 10 -6.3获取A/D的转换值- 10 -6.4主函数- 11 -6.5子函数- 15 -第七章 结论- 23 -第八章 心得体会- 24 -参考文献- 25 -第一章 引言由于Linux系统是开源系统,其内核和各种开发工具都可以从网络上轻易获取,使其在嵌入式系统的开发中得到了越来越广泛的应用。但Linux系统本身并没有对种类繁多的硬件设备都提供现成的驱动程序,特别是由于工程应用中的灵活性,其驱动程序更是难以统一,这时就需开发一套适合于自己产品的设备驱动,使得Linux设备驱动程序的开发在整个嵌入式系统开发工作中占有很重要的地位。而基于ARM架构的中高档的嵌入式系统应用已经非常广泛,本文针对现在非常流行的一款三星公司生产的ARM9嵌入式微处理器S3C2440,在Linux操作系统下实现了多路AD转换的驱动,通过该驱动程序实例,介绍在Linux系统下驱动程序编写的一般方法,包括驱动程序和测试程序的编写。1硬件设备硬件系统核心部分采样的是韩国三星公司设计的基于ARM9的嵌入式微处理器S3C2440。S3C2440配合SDRAM、FLASH、USB、网口和串口等就构成了基本的ARM嵌入式硬件平台。本文针对现在非常流行的一款三星公司生产的ARM9嵌入式微处理器S3C2410,在Linux操作系统下实现了多路AD转换的驱动,通过该驱动程序实例,介绍在Linux系统下驱动程序编写的一般方法,包括驱动程序和测试程序的编写。第二章 设计目的通过课程设计,熟悉基于ARM微处理器的嵌入式系统开发的过程,掌握嵌入式系统开发的A/D 接口原理,掌握S3C2410的AD相关寄存器的配置及编程应用方法,锻炼实践动手能力和团队协作能力。第三章 设计原理A/D 转换器是模拟信号和CPU 之间联系的接口,它是将连续变化的模拟信号转换为数字信号,以供计算机和数字系统进行分析、处理、存储、控制和显示。在工业控制和数据采集及许多其他领域中,A/D 转换是不可缺少的。按照转换速度、精度、功能以及接口等因素,常用的A/D转换器有以下两种:(1)双积分型的A/D转换器双积分型也称为二重积分式,其实质是测量和比较两个积分的时间,一个是对模拟信号电压的积分时间T,此时间常是固定的,另一个是以充电后的电压为初值,对参考电源Vn的反向积分,积分电容被放电至零,所需的时间Ti。模拟输入电压Vi与参考电压Vref之比,等于上述两个时间之比。由于Vref、T时间固定,而放电时间Ti可以测出,因而可以计算出模拟输入电压的大小。(2)逐次逼近型的A/D转换器逐次逼近型也称为逐位比较式,它的应用比积分型更为广泛,通常主要有逐次逼近寄存器SAR、D/A转换器、比较器以及时序和逻辑控制等部分组成。通过逐次把设定的SAR寄存器中的数字量经D/A转换后得到电压Vc与待转换模拟电压V0进行比较。比较时,先丛SAR的最高位开始,逐次确定各位的数码应为1还是0,而得到最终的转换值。其工作原理为:转换前,先将SAR寄存器各位清零,转换开始时,控制逻辑电路先设定SAR寄存器的最高位为1,其余各位为0,此值经D/A转换器转换成电压Vc,然后将Vc与输入模拟电压Vx 进行比较。如果Vx 大于等于Vc,说明输入的模拟电压高于比较的电压,SAR最高位的1应保留;如果Vx小于Vc,说明SAR的最高位应清除。然后在SAR的次高位置1,依上述方法进行D/A转换和比较。如此反复上述过程,直至确定出SAR寄存器的最低位为止,此过程结束后,状态线改变状态,表明已完成一次转换。最后,逐次逼近寄存器SAR中的数值就是输入模拟电压的对应数字量。位数越多,越能准确逼近模拟量,但转换所需的时间也越长。第四章 关键技术4.1 ARM9处理器新一代的ARM9处理器,通过全新的设计,采用了更多的晶体管,能够达到两倍以上于ARM7处理器的处理能力。这种处理能力的提高是通过增加时钟频率和减少指令执行周期实现的。ARM9 系列包括三种处理器:ARM926EJ-S、ARM946E-S 和 ARM968E-S。(1)ARM968E-S面积最小、包含 DSP 增强功能的 ARM9 处理器,针对低功耗、数据密集型、嵌入式实时应用。面积最小、功耗最低的 ARM9 处理器是众多实时类型应用的理想之选。通过可轻松从标准接口集成的紧密耦合内存,该处理器可高效工作。(2)ARM946E-S具有 MPU 的 DSP 增强型高速缓存处理器,针对运行 RTOS 的实时应用。一种具有可选高速缓存接口以及完整的内存保护单元的实时处理器。对于大部分代码位于主存储器的应用,该处理器非常有用,它按需加载到高速缓存中,同时关键的异常处理代码和数据仍本地保留在紧密耦合内存中。(3)ARM926EJ-S具有 Java 加速、DSP 扩展和 MMU 的应用处理器,针对基于操作系统的应用。ARM926EJ-S 处理器为入门级处理器,可支持完全版操作系统,其中包括 Linux、Windows CE 和 Symbian。因此,此处理器是众多需要完整图形用户界面的应用的理想之选1。4.2嵌入式C语言开发技术由于现在越来越多的产品都采用嵌入式开发,所完成的计算和控制工作也日趋复杂,而嵌入式系统是一种资源十分有限的系统(这主要表现在程序存储器资源的不足上),因此在程序设计时如何使用好这些有限的资源就显得十分重要。用C语言变成虽然具有许多的优点,但是生成的代码相对较长,若编程技术不好,生成的代码有可能比汇编语言生成的代码长几倍,因而对编程者来说,应该注意到嵌入式C语言和一般意义上的标准C语言的区别,对程序进行适当的优化。 嵌入式C语言编程不同于一般的C语言编程的一个显著特点,就是要和程序存储器资源结合起来。虽然其提供的数据类型十分丰富,但其中只有bit和char等数据类型是机器语言直接支持的数据类型,用此类数据类型的语句所生成的代码较短;而其他的数据类型如整形、浮点型等数据要有一定的内部程序或内部函数的支持,用该类数据类型的语句生成的代码则相对教程。4.3 ADS开发环境1.运行ADS1.2集成开发环境(CodeWarrior for ARM Developer Suite),点击File|New,在New对话框中,选择Project栏,其中共有7项,ARM Executable Image是ARM的通用模板。选中它即可生成ARM的执行文件。同时,还要在,Project name栏中输入项目的名称,以及在Location中输入其存放的位置。按确定保存项目。2.在新建的工程中,选择Debug版本,使用Edit|Debug Settings菜单对Debug版本进行参数设置。3.点击Debug Setting 按钮,选中Target Setting项,在Post-linker栏中选中ARM fromELF项。按OK确定。这是为生成可执行的代码的初始开关。4.点击ARM Assembler ,在Architecture or Processer 栏中选ARM920T。这是要编译的CPU核。5.点击ARM C Compliler ,在Architecture or Processer栏中选ARM920T。这是要编译的CPU核。6.点击ARM linker ,在outpur栏中设定程序的代码段地址,以及数据使用的地址。RO Base栏中填写程序代码存放的起始地址,RW Base栏中填写程序数据存放的起始地址。该地址是属于SDRAM的地址。在options栏中,Image entry point要填写程序代码的入口地址,其他保持不变,如果是在SDRAM中运行,则可在0x300000000x33ffffff中选值,这是64M SDRAM的地址,但是这里用的是起始地址,所以必须把你的程序空间给留出来,并且还要留出足够的程序使用的数据空间,而且还必须是4字节对齐的地址(ARM状态)。通常入口点Image entry point 为0x30000000,ro_base也为0x30000000。在Layout栏中,在Place at beginning of image框内,需要填写项目的入口程序的目标文件名,如,整个工程项目的入口程序是2410init.s,那么应在Object/Symbol处填写其目标文件名2410init.o,在Section处填写程序入口的起始段标号。7.在Debug Setting对话框中点击左栏的ARM fromELF项,在Output file name栏中设置输出文件名*.bin,前缀名可以自己取,在Output format 栏中选择Plain binary,这是设置要下载到flash中的二进制文件。8. 到此,在ADS1.2中的基本设置已经完成,可以将该新建的空的项目文件作为模板保存起来。首先,要将该项目工程文件改一个合适的名字,如S3C2410 ARM.mcp等,然后,在ADS1.2软件安装的目录下的Stationary 目录下新建一个合适的模板目录名,如,S3C2410 ARM Executable Image,再将刚刚设置完的S3c2410 ARM.mcp项目文件存放到该目录下即可。这样,就能看到该模板。、9.新建项目工程后,就可以执行菜单Project|Add Files把和工程所有相关的文件加入,ADS1.2不能自动进行文件分类,用户必须通过Project|Create Group来创建文件夹,然后把加入的文件选中,移入文件夹。或者鼠标放在文件填加区,右键点击,即出!先选Add Files,加入文件,再选Create Group,创建文件夹,然后把文件移入文件夹内。读者可根据自己习惯,更改Edit|Preference窗口内关于文本编辑的颜色、字体大小,形状,变量、函数的颜色等等设置。4.4基于ARM9的硬件ARM9系统的硬件设计,是一项复杂的系统工程,必须有坚实的准备知识,包括电路基础、模拟电路、数字电路、微机原理、接口技术、嵌入式原理、ARM系统原理等等。不仅需要硬件相关的知识,而且需要软件方面的知识,如操作系统。由于是复杂的硬件系统的设计,还需要掌握EDA软件。此外,由于硬件开发还涉及焊接、调试等工序,所以还应该对元器件的封装、电气特性等有所了解,并掌握焊接技术,能对一般的贴片元件进行手工焊接。这方面的知识需要在实践中积累经验,很难一蹴而就。做ARM9系统的硬件设计,一般采用六层板,成本较高。为了避免因设计的错误而付出沉重的代价,应从简单的硬件设计做起,有助于提高ARM9系统设计的成功率。第五章 程序流程驱动程序的组成及设计 驱动程序是操作系统内核与硬件设备的直接接口,驱动程序屏蔽了硬件的细节,使得应用程序可以像操作普通文件一样对硬件设备进行操作。Linux将设备分为字符设备,块设备和网络设备三种。A/D转换是属于字符设备。设备驱动程序主要完成如下功能4:(l)对设备初始化和释放;(2)把数据从内核传送到硬件和从硬件读取数据;(3)读取应用程序传送给设备文件的数据并回送应用程序请求的数据;(4)检测和处理设备出现的错误。在系统内部,I/O设备的存取是通过一组固定的入口点完成与外部的通信,这些入本驱动程序的工作流程如图1所示,主要由3大模块组成。5.1初始化和结束程序在驱动程序设计中通常通过使用_init和_exit声明来定义用户自己的初始化函数和清除函数,然后使用module_init(mydev_int)和module_exit(mydev_cleanup)来完成设备驱动程序的注册和卸载(其mydev_init和mydev_cleanup函数即为用_init和_exit声明的初始化函数和清除函数)。在本驱动程序中初始化函数adc_init()主要完成一些初始化的工作,包括对硬件设备的初始化、中断的注册、设备的注册等,初始化部分仅在驱动程序初始化的时候被调用一次,而缷载函数则完成相反的功能。5.2服务于I/O请求的函数在系统内部,I/O设备的存取是通过一组固定的入口点完成与外部的通信,这些入口点通过一个file_operations数据结构在注册设备文件时与外部调用函数关联起来,它是字符设备驱动程序的核心,结构中的每个成员名字都对应着一个系统调用。该结构实际就是声明了针对各种设备不同操作的函数指针,Linux下驱动程序的大部分工作,实际上就是完成上述各种操作方法的函数。但是实际的驱动程序中并不需要为每一个操作都编写相应的实现代码,对于不需要的操作,可在初始化file_operations结构时在相应的位置赋予空指针NULL即可5。本驱动通过调用open入口点,为将要进行的I/O操作做好准备工作,包括初始化中断事件变量、设置AD转换通道等,在此通过一个for循环来设置4个AD转换通道,以实现打开4个AD通道的要求;通过read入口点设置ADCCON控制寄存器启动AD转换,并设置中断事件变量使程序进入等待转换结束,在中断事件激活后,通过copy_to_user内核函数将转换结果传送到用户空间变量指针来完成整个A/D转换。AD转换大部分过程都是在adc_read()函数(它为应用程序系统调用read函数时调用的函数)里实现的,它是AD转换的主体函数,在此函数中通过判断通道号实现了多通道AD转换,部分实现代码如下:staticssize_tadc_read(structfile*filp,char*buffer,size_tcount,loff_t*ppos)START_ADC_AIN(adcdev.channel,adcdev.prescale);/启动AD转换wait_event_interruptible(adcdev.wait,ev_adc);/通过中断的方式等待结果if(converter_channel=3)/通道的选择converter_channel=0;elseconverter_channel+;adcdev.channel=converter_channel;value=adc_data;intr=copy_to_user(buffer,str,len);/将内核空间中的数据拷贝到用户空间,以供应用程序使用5.3中断服务程序在Linux系统中,中断是由系统来管理与维护的。中断服务子程序在初始化函数中调用irq_request函数与相应中断号关联,并将该中断的相关信息添加到系统的中断信息列表中,以便在中断发生时供系统检索。目标机上完成某一AD转换后,将产生一中断号为IRQ_ADC_DONE的中断,系统将自动检索并调用相应的中断服务子程序。此处的中断服务子程序完成ADC寄存器中读取转换结果(通过adc_data=ADCDAT0&0x3ff;实现)、激活中断事件变量,从而read函数结束等待状态,返回AD转换结果本次课程设计仅使用实验教学系统的CPU板。在进行本实验时,LCD电源开关、音频的左右声道开关、AD通道选择开关、触摸屏中断选择开关等均应处在关闭状态。在PC机并口和实验箱的CPU板上的JTAG接口之间,连接仿真调试电缆。使用串口线连接PC机串口1和实验箱CPU板的串口,使用直连线连接底板串口2和PC机上的串口2之间的电缆。检查连接是否可靠,可靠后,接入电源线,系统上电。拨码开关SW3为选中的A/D转换的通道,值得注意的是本实验系统八个通道可以同时采集一个信号源。实验时要选中采集的通道号,即对应的SW3开关拨到ON状态。例如SW3的1拨到ON状态,说明用AD转换器的通道1采集,如果,8个通道全部选择为ON,则表示用8个通道采集。本实验程序使用通道1采集数据,所以,SW3的1应该拨到ON状态。要给ADIN一个输入信号,可以是底板上的SQUARE信号和SINE信号,也可是外部信号,但是必须注意,接外部电压信号时,要共地,以及信号的电压范围为02.5V打开ADS1.2开发环境,连接编译运行通过后,全速运行映象文件。打开LCD电源开关, 检查SW3上选择的是通道几。确认后,观察LCD上1通道当前采集的情况。由于液晶的显示速度比波型慢许多,所以要暂停程序才会看到比较清楚的波形。由于信号源输出后,电压经过缩放和偏置处理。使得的ARM CPU板所采集到的电压值的变化范围不足02.5V,故而采集到的数字值,不能满程。但这些不会影响实验原理的显示。第六章 主要源代码6.1定义与A/D转换相关的寄存器#define radcCON (*(volatitle unsigned * )0x58000000) /ADC控制寄存器#define radcTSC (*(volatitle unsigned * )0x58000004) /ADC控制寄存器#define radcDLY (*(volatitle unsigned * )0x58000008) /ADC控制寄存器#define radcDAT0 (*(volatitle unsigned * )0x5800000c) /ADC控制寄存器#define radcDAT1 (*(volatitle unsigned * )0x58000010) /ADC控制寄存器6.2对A/D转换器进行初始化Void AD_init(unsigned char ch)rADCDLY=100;/ADC启动或间隔延时rADCTSC=0; /选择ADC模式rADCCON=(114)|(496)|(ch3)|(02)|(07) return 0;For(i=0;i16:i+) Radccon|=0x1;Radccon=radccon&0xffc7|(ch4);6.4主函数#include .lcddrvinclcd.h#include .lcddrvinclcdlib.h#include .guiglibglib.h#include target.h#include 2410LIB.h#include 2410addr.h#include adc.hextern GUI_FONT GUI_Font8x16;#define Length 640void ShowWave(short* buffer, int p, short* buffer2)int i, j;j = 0;/ Set_Color(GUI_BLUE);/Fill_Rect(0,0,319,239); for (i = p - 1; i Length; i+) Draw_Point(j, buffer2i); j+; for (i = 0; i p - 1; i+) Draw_Point(j, buffer2i); j+; Set_Color(GUI_RED); j = 0;for (i = p; i Length; i+) Draw_Point(j, bufferi); j+; for (i = 0; i p; i+) Draw_Point(j, bufferi); j+; Uart_Printf(%dn, bufferi);void ShowWavebuffer(short* buffer) int i, j; j = 0;Set_Color(GUI_BLUE);Fill_Rect(0,0,639,479);Set_Color(GUI_RED);for (i = 0; i Length; i+) Draw_Point(i, bufferi); void Main(void) int i, p = 0; unsigned short bufferLength; unsigned short buffer2Length; Target_Init(); GUI_Init(); Set_Color(GUI_BLUE); Fill_Rect(0,0,639,479); Set_Color(GUI_RED); Draw_Line(0, 250, 639, 250);Set_Font(&GUI_Font8x16); /设定字体类型APISet_Color(GUI_WHITE);Set_BkColor (GUI_BLUE); /设定背景颜色APIFill_Rect(0,0,639,3);Fill_Rect(0,0,3,479);Fill_Rect(636,0,639,479); Fill_Rect(0,476,639,479); Disp_String (ADC DEMO,(640 - 8 * 8) / 2, 50); for (i = 0; i = Length) p = 0; while (1) p = 0; for (i = 0; i Length; i+) bufferp = Get_AD(0); p+; p = 0;for (i = 0; i Length; i+) Uart_Printf(%dn, bufferp); p+; p = 0; for (i = 0; i Length; i+) bufferp = AD2Y(bufferp); p+; p = 0; for (i = 0; i 7) return 0; for(i=0;i16;i+) rADCCON |= 0x1; /启动 A/D 转换 rADCCON = rADCCON & 0xffc7 | (ch4);/*采样4次,平均处理*/ int i; int val=0; if(ch7) return 0; for(i=0;i4;i+) rADCCON |= 0x1; /启动 A/D 转换 rADCCON = rADCCON & 0xffc7 | (ch2); /*采样1次,平均处理 */ int i; int val=0; if(ch7) return 0;for(i=0;i1;i+) rADCCON |= 0x1; /启动 A/D 转换 rADCCON = rADCCON & 0xffc7 | (ch7) return 0; for(i=0;iADCount;i+) rADCCON |= 0x1; /启动 A/D 转换while (rADCCON & 0x1); /避免第一个标志出错while(!(rADCCON&0x8000); /避免第二个标志出错ArrayDat0i = (rADCDAT0 & 0x03ff);Delay(1); val = GetDat0(p); return (val); void AD_Init(unsigned char ch) rADCDLY = (100); / ADC Start or Interval Delay 0x100rADCTSC = 0; /设置成为ADC模式rADCCON= (114)|(496)|(ch3)|(02)|(01)|(0); /设置ADC控制寄存器int AD2Y(int ady) / 把AD值转换成坐标值 yreturn LCD_YSIZE * (AD_TOP - ady) / (AD_TOP - AD_BOTTOM);void selectsort(int* r,int n) /r is struct rec,选择排序 int i,j,k; int w;/struct recfor(i = 0; i n - 1; i +) k = i; for (j = i + 1; j n; j +) if (rj rk) k = j; if (k != i) w=ri;/交换 ri=rk; rk=w; #if (isDebug = 1) Uart_Printf(Sort:); for (i = 0; i n; i+) Uart_Printf(%d, , ri); Uart_Printf( endn); #endifint GetDat0(int* p) int Dat0; /const int ADCount = 10; int tmp9;/ADCount - 1 int i, k, diftag = 0;struct ARRAYCMP int difsize; int continuecount; ArrayCmp9;/ADCount - 1 selectsort(p, ADCount); /将采集到的数据排序(由小到大)for (i = 0; i ADCount - 1; i +) tmpi = pi + 1 - pi; /tmp存储各点之间的差值 #if (isDebug = 1) Uart_Printf(tmp:n ); for (i = 0; i ADCount - 1; i+) Uart_Printf(%d,tmpi); Uart_Printf(n); #endif /fill table /ArrayCmp是一个表格,表格的第一列存储各点之间的差值, /第二列存储相同的点连续存放的个数 /* 举例: tmp : 2,0,0,0,2,0,0,2,2 ArrayCmp如下: 下标差值连续个数 020 102 20-2 30-1 420 501 60-2 721 */ ArrayCmp0.difsize = tmp0; ArrayCmp0.continuecount = 0; k = 0; for(i = 1; i ADCount - 1; i+) if (tmpi = tmpi - 1) & (diftag = 0) ArrayCmpi.difsize = tmpi; ArrayCmpi.continuecount = -2; ArrayCmpi - 1.continuecount = 1; diftag = 1; k = i - 1; else if (tmpi = tmpi - 1) & (diftag = 1) ArrayCmpi.difsize = tmpi; ArrayCmpi.continuecount = -1; ArrayCmpk.continuecount += 1; diftag = 1; else /(tmpi != tmpi - 1) ArrayCmpi.difsize = tmpi; ArrayCmpi.continuecount = 0; diftag = 0; #if (isDebug = 1) Uart_Printf(ArrayCmp:n ); for
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025版肉牛养殖产业投资基金合作合同模板
- 2025版国际贸易货物退税代理合同书
- 2025版水电安装与电气设备调试合同
- 2025年汽车维修店租赁合同(包含品牌使用权)
- 2025年度围堰工程施工期间气象服务与信息共享合同
- 2025版住宅小区物业交接与业主权益保障合同
- 2025单身公寓装修合同范本及注意事项
- 2025草原旅游开发合作协议书范本
- 吉水县园区开发建设有限公司及下属子公司2025年面向社会公开招聘运营岗、工程管理岗备考练习题库及答案解析
- 2025年度医疗机构护理人员临时雇佣合同
- 外研版(2024)八年级上册英语Unit 1 This is me 教案(共6课时)
- 2025年公安辅警笔试题目题库(答案+解析)
- 2025年外事办公室翻译招聘面试(俄语)预测题及答案
- 消保化解案例课件
- 2025年跨境电商物流服务佣金结算合作协议
- 2025年度东营市专业技术人员继续教育公需科目试卷及答案
- 用浪浪山正确打开开学第一课~课件
- 数学新人教版七年级上册校本作业
- 高中单词速记3500表打印
- 客观情况发生重大变化解除劳动合同(共3页)
- PK-PD结合效应模型PPT课件
评论
0/150
提交评论