【摘 要】本次实训的目的在于利用ARM系统进行简单的系统设计。而在这次实训
中,我利用ARM系统设计函数信号发生器,其基本步骤如下:
总体方案的设计与选择:根据设计任务要求和给定的条件,分析所要设计电路应完成的功能,并将总体功能分解成若干个单元功能,分清主次和相互的关系,形成若干单元功能然后再组成总体方案。
程序的编写:编写满足设计要求的程序并写入LPC2138芯片中,通过系统实现对电路的控制,从而达到设计的要求。
程序的调试:在课程设计的实践过程中程序的调试占有非常重要的地位,它是最基础的阶段,也是将理论转换为实际的一个关键过程,因此调试时要谨慎小心的进行,从各方面考虑不能产生结果的原因。
本次实训制作的是函数信号发生器:这是一个在实验和实际应用中都有重要作用,此
次实训是函数信号发生器的基本功能进行设计。
【关键词】ARM7、LPC2138、DAC、定时器、GPIO、中断、按键、蜂鸣器、数字
示波器、杜邦线
1
目 录
1. 设计目的与要求 „„„„„„„„„„„„„„„„„„1
1.1 设计目的 „„„„„„„„„„„„„„„„„„„3 1.2设计要求„„„„„„„„„„„„„„„„„„„3
2. 方案设计与论证…………………………………………………3
1、设计分析„„„„„„„„„„„„„„„„„„„„„„„„3 2、方案论证„„„„„„„„„„„„„„„„„„„„„„„„3 3、方案选择„„„„„„„„„„„„„„„„„„„„„„„„3
3.硬件电路„„„„„„„„„„„„„„„„„„„„„3
1、器件„„„„„„„„„„„„„„„„„„„„„„„„3 2、器件连接说明„„„„„„„„„„„„„„„„„„„„„„„4
4.软件设计„„„„„„„„„„„„„„„„„„„„„„„„5 5调试„„„„„„„„„„„„„„„„„„„„„„„7 6.结论与心得„„„„„„„„„„„„„„„„„„„„„„„7 7.参考文献„„„„„„„„„„„„„„„„„„„„„„„„7 附录 实验程序„„„„„„„„„„„„„„„„„„„„„7
2
1、设计的目的与要求
1.1 设计目的
(1)本次课程设计是在学习了《深入浅出ARM7》课程之后综合利用所学知识完成一个应用系统设计并在实验室实现。
(2)通过实训,加深了对理论知识的理解,并且把理论知识应用在实际中,培养自己的动手能力和解决实际问题的能力,进一步熟悉和掌握ARM的结构及工作原理。
(3)熟悉ARM Developer suitv1.2的调试和仿真,提高软件调试的能力,通过对实际程序的设计和调试,进一步掌握模块化程序设计方法和调试技术。
(4)通过完成一个程序开发的完整过程,了解开发一个ARM应用系统的全过程,为今后从事相应事业打下基础。
1.2 设计要求
(1)用D/A输出产生幅度可调的正弦波、方波、三角波、锯齿波。 (2)用定时器对波形的输出频率进行控制。
(3)利用KEY3、KEY4、 KEY5、 KEY6对正弦波、方波、三角波、锯齿波进行控制,并且要求在显示一种波形的时候,能在仿真的LED数码显示器中显示出当前波形的名称。
(4)通过按键KEY1和KEY2,可对波形的幅度进行增加和减小的调节,并且要设置幅度的上下限。
2、方案的设计与论证
2.1 设计分析
此次实训的目的在于用ARM7的知识点,在EasyARM2131开发板中进行波形发生器的设计,产生能调幅的正弦波、方波、三角波、锯齿波。并且能实现各种波形的定时切换和显示波形名称。
2.2 方案论证
方案一:采用ARM的PWM功能产生方波,方波的频率可以达到几百K,外接滤波电
路,通过选频,得到各种波形。可以通过PWM直接调频调幅,也可以通过外接电路实现。 方案二:利用的EasyARM2131开发板中的D/A转换器产生波形。通过定时器来控制频率。D/A输出的波形很稳定。
2.3 方案选择
在第一种方案,虽然频率范围比较宽,外接电路也很简单,但实现任意波形有些复杂,
而且外接电路固定后,难以改变波形。
在第二种方案中可以通过编写函数,方便的得到想要的波形,不需要外接的电路,而且输出的波形很稳定。
考虑到输出波形的稳定性和自己对波形函数编写的熟悉。我选择了第二种方案。
3、硬件电路部分
3.1 器件原理
3
(1)EasyARM2131开发板是广州周立功公司设计的EasyARM系列开发套件之一,采用了 PHILIPS公司基于ARM7TDMI-S 核、单电源供电、LQFP封装的LPC2131,具有JTAG 仿真调试、ISP编程等功能。 开发板上提供了一些键盘、LED、蜂鸣器等常用功能部件,还具有RS232接口电路、I2C 存储器电路。另外,用户也可以更换兼容的CPU进行仿真调试,如LPC2132、LPC2138、 LPC2142等。灵活的跳线组合(开发板内使用的所有I/O均可断开连接),还有用户I/O接 口,极大地方便了用户进行32位ARM嵌入式系统的开发实验。
EasyARM2131开发板布局图如下图所示。
(2) EasyARM2131开发板可以使用与LPC2131兼容的CPU进行仿真调试,倘若使用 LPC2132/LPC2138芯片,则可以其10位D/A转换器进行DAC输出实验。D/A转换器的其参考电压与A/D转换器的相同,EasyARM2131开发板的参考源选择如图1.13所示。如图1.15所示,通过JP3和JP4选择连接,LPC2132/LPC2138的Aout输出经过R14连接到AD0.1,这样就可以直接使用AD0.1来检测Aout输出电压值。
当需要将DAC输出连接到用户的电路时,先把JP3选择短接到“P0.25”端,然后从用
4
户接口J6引出Aout信号,如图1.16所示。
D/A转换器
具有以下特性:
10位数模转换器; 电阻串连结构; 缓冲输出; 掉电模式;
选择的转换速率与功率有关。
注:仅LPC2132/2134/2136/2138有D/A。 他的寄存器如下:
写程序时,只要将要转化的值赋给DACR的6到15位,然后定时器定时给他转换的时间。则可以完成转化。我们采用10的转化,也即1024个采样点的转化,设定时时间为t0,则波形的频率计算方法为:f=1/(1024*t0)。设赋的值为value,则波形的幅度计算方法为A=VALUE/1024*3.3. (3)中断
LPC2138 通过向量中断控制器(VIC )管理中断。外设中断信号需要经过2 个开关才能
5
到达ARM 内核,真正产生异常,逻辑示意图如下图所示。如果在VIC中使能了相应外 设的中断,外设中断才能到达VIC并向内核发送中断请求;只有使能了内核中断IRQ或者 FIQ,内核才能真正产生异常。硬件图如下
中断的过程示意图如下:
(4)按键的连接图
不按下时为高电平,按下时变为低电平 3.2 器件连接说明
(1)由于D/A转换时要用到基准电压,所以JP5要连接verf; (2)KEY1连接P0.16;KEY2连接P0.17;KEY3连接P0.18, KEY4连接P0.19, KEY5连接P0.20,KEY6连接P0.21。
(3)数字示波器连接DAC端口和GND端。
4、软件部分设计
系统软件采用C语言编程,程序详情请看程序附录
程序的流程图如下:
6
主程序开始设置P0[7:4]引脚连接SPIO;P0.0, P0.1引脚连接UART0设置P0.25连接DAC设置P0.16,P0.17连接GPIO串口0初始化SPI初始化设置74HC595片选为输出设置蜂鸣器端口为输出设置蜂鸣器端口为高电平定义table数组设定DAC的时间最大为1US,最大的电流为700UA使能IRQ中断定时器初始化;时钟分频、定时器初值、匹配后产生中断、定时时间、使能定时器VIC中断向量控制器设置;设置为向量中断;分配中断通道;设置中断服务程序地址;使能Time0中断A7
A是判断count是否为-1count的值为9否判断cnt的值是否为9是仿真的LED数码器中(10秒内开始值)显示SIN否判断cnt的值是否为1000009是仿真的LED数码器中(10秒到20秒内的开始值)显示SANJIAO否判断cnt的值是否为2000009是仿真的LED数码器中(20秒到30秒内的开始值)显示FANG否判断cnt的值是否为3000009是仿真的LED数码器中(30秒到40秒内的开始值)显示JUCHI否判断cnt的值对100000求余是否为0是是幅度变量(判断是否到达1秒)判断KEY1是否按下V加2否否是判断KEY2是否按下幅度变量V减少2否是判断v的值是否大于26幅度变量V值为13否是判断v的值是否小于2幅度变量否V值为13发送显示倒计时数据判断count的值是否为9是蜂鸣器蜂鸣否是判断count的值是否为8蜂鸣器停止蜂鸣否8
Timer0中断服务程序开始cnt变量加1判断cnt是否小于1000000是示波器上显示(是否在10秒之内)正弦波否判断cnt是否大于1000000并且小于2000000是示波器上显示(是否在10秒和20秒之间)三角波否判断cnt是否大于2000000并且小于3000000是示波器上显示(是否在20秒和30秒之间)方波否判断cnt是否大于3000000并且小于4000000是示波器上显示(是否在30秒和40秒之间)锯齿波否变量cnt为0清除Timer0中断标志通知VIC中断处理结束返回中断原点
9
4、调试过程及结果
按照器件连接说明连接好EasyARM2131开发板上的跳线后,再将数字示波器的探头分别接在DAC和GND端,运行程序,开始调试。在一开始时,由于用定时器设置的波形频率太小,导致在示波器上观察到波形不太稳定而且线条很粗,于是自己就试着改定时器上的时间来增大频率。但是后来又发现把波形频率调大了,波形仍不能很好。想了很久,都不能明白原因,经老师指点后,发现是在定时中断的子程序那里执行了很多条语句,那些语句是用来在仿真的LED数码显示器上显示函数名称和判断是否有按键的作用。后来才明白,原来在过短的时间内执行太多的语句,会影响系统的稳定性和效率,因此波形才会不好。所以我将那些语句放到了主程序中,问题就得到了解决,波形也很好了。
程序的运行结果是在EasyARM2131开发板上不同的按键控制不同类型的波形,从KEY3到KEY6按下,示波器上的波形就变换一次。因此示波器上会根据人为的控制变换不同的波形,显示正弦波,三角波,方波,锯齿波。并且在仿真的LED数码显示器中显示相应的波形名称。当示波器上显示正弦波的时候,在仿真的LED数码显示器中显示SIN,当示波器上显示三角波的时候,在其上显示SANJIAO,当显示方波的时候,在其上显示FANG,当在示波器上显示锯齿波的时候,在其上显示JUCHI。并且在波形显示的过程中,按键KEY1,KEY2键可以分别增加和减少波形的幅度,增加减少到一定的上下限幅度时又会跳回到原来的幅度。
5、课程设计体会
经过本周的实训之后,我对课本上的ARM知识掌握得更好,并在实训过程中,不断的发现问题,解决问题,提高了自己动手和编程的能力。在编写程序的过程中,我更加深入的了解了正弦波,三角波,方波和锯齿波的编写方法和EasyARM2131开发板上的D/A转换器的用法,通过不断的调试程序,也掌握了用定时器控制波形输出频率的方法。在输出波形的不稳定问题上,我困惑了很久,经过老师的指点下,让我明白了,要使波形输出的稳定,首先电源电压要稳定,然后就是在程序的编写中,不能在一小段时间内执行过多的指令。这样会影响系统的效率。通过解决了以上问题,波形就变得很好了。
本次实训还让我认识到流程图的重要性,以前在编程前,我就喜欢按照功能写语句,没先把流程图写出来。但是在此次实训时,这让我走了很大的弯路,有很多的问题是因为自己太过于空想,而把一些语句放在了错误的位置。当把流程图画出来之后就可以明显发现问题的所在了,也很快的解决了问题。所以我认识到,以后要编写程序时,先写流程图是很有必要的。
6、参考文献
(1)《深入浅出ARM7》 北京航空航天大学出版社 (2)《C程序设计完全手册》 人民邮电出版社 (3)《C程序设计》 清华大学出版社 (4)《电子报合订本(上)》 四川出版集团—四川科学技术出版社 (5)《数字电子技术基础》 高等教育出版社
10
附录:
实训程序
/********************************************************************************************************/ #include \"config.h\" #include \"math.h\" #include \"stdio.h\"
typedef struct UartMode { uint8 datab; // 字长度 5/6/7/8 uint8 stopb; // 停止位 1/2 uint8 parity; // 奇偶校验 0-无校验, 1-奇校验, 2-偶校验 }UARTMODE;
const uint32 KEY1 = 1 << 16; // P0.16连接KEY1 const uint32 KEY2 = 1 << 17; // P0.17连接KEY2 #define BEEP 1 << 15 // P0.15控制蜂鸣器,低电平蜂鸣 uint32 cnt=0,count=9; uint16 delay; uint16 l=0;
uint16 k=0,b,c,da=1; uint16 zj_flag=0; uint16 table[1024]; uint16 a=0,v=13;
#define UART_BPS 115200 // 通讯波特率115200
#define HC595_CS (1 << 29) // P0.29口为74HC595的片选 /*
******************************************************************************************************* ** 函数名称 :UART0_Init()
** 函数功能 :初始化串口0:波特率115200,8位数据位,1位停止位,无奇偶校验。 ** 入口参数 :无 ** 出口参数 :无
******************************************************************************************************* */
uint8 const DISP_TAB[10] = {
// 0 1 2 3 4 5 6 7 8 9 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8, 0x80,0x90 };
void MSPI_Init(void) { PINSEL0 = (PINSEL0 & (~(0xFF << 8))) | (0x55 << 8) ;
11
SPCCR = 0x52; // 设置SPI时钟分频 SPCR = (0 << 3) | // CPHA = 0, 数据在SCK 的第一个时钟沿采样 (1 << 4) | // CPOL = 1, SCK 为低有效 (1 << 5) | // MSTR = 1, SPI 处于主模式 (0 << 6) | // LSBF = 0, SPI 数据传输MSB (位7)在先 (0 << 7); // SPIE = 0, SPI 中断被禁止 }
uint8 MSPI_SendData(uint8 data) {
IOCLR = HC595_CS; // 片选74HC595
SPI_SPDR = data;
while( 0 == (SPI_SPSR & 0x80)); // 等待SPIF置位,即等待数据发送完毕
IOSET = HC595_CS; return(SPI_SPDR); }
void SendByte (uint8 data) { U0THR = data; while ((U0LSR & 0X20) == 0); // 等待数据发送 }
void PC_DispChar (uint8 no, uint8 chr) { SendByte(0xff); SendByte(0x80); SendByte(no); SendByte(chr); SendByte(0x00); }
uint8 UART0_Init (uint32 baud, UARTMODE set) { uint32 bak; // 参数过滤 if ((0 == baud) || (baud > 115200)) return (0); if ((set.datab < 5) || (set.datab > 8)) return (0); if ((0 == set.stopb) || (set.stopb > 2)) return (0); if (set.parity > 4) return (0);
12
// 设置串口波特率 U0LCR = 0x80; // DLAB=1 bak = (Fpclk >> 4) / baud; U0DLM = bak >> 8; U0DLL = bak & 0xff; // 设置串口模式 bak = set.datab - 5; if (2 == set.stopb) bak |= 0x04; if (0 != set.parity) { set.parity = set.parity - 1; bak |= 0x08; } bak |= set.parity << 4; U0LCR = bak; return (0); }
/********************************* 正弦
****************************************************/ void sin_wave(void) { a =(a+1)%1024;
DACR=((table[a]*v/26)<<6); //把值送入DACR计算电压 } /*
*********************************************************** **三角波
************************************************************* */
void trip_wave(void) {
if (zj_flag==0) //三角波的递增 { b+=2; if (b>1020) {
13
zj_flag=1; } } else { //三角波的递减 b-=2; if (b<10) { b=10; zj_flag=0; } } DACR=((b*v/26)<<6); //把值送入DACR计算电压 }
/********************************* 方波
****************************************************/ void fang_wave(void) {
k++; if(k<512) c=512; //方波的高电平 else c=10; //方波的低电平 if(k>1024) k=1; DACR=(c*v/13<<6); //把值送入DACR计算电压 }
/************************************************************ 锯齿波
**************************************************************/ void juchisave()
{ da++; //锯齿波的递增 if(da>=1024) da=1;
DACR=((da*v/26)<<6); //把值送入DACR计算电压 } /*
*********************************************************************************************************
14
** 函数名称 :IRQ_Timer0()
** 函数功能 :定时器0中断服务程序,取反LED9控制口。 ** 入口参数 :无 ** 出口参数 :无
********************************************************************************************************* */
void __irq IRQ_Timer0(void) {
cnt++;
if(cnt<=1000000) //判断是否在10秒内
sin_wave(); //显示正弦波
else if((cnt>1000000)&(cnt<=2000000)) //判断是否在10—20秒内
trip_wave(); //显示三角波
else if((cnt>2000000)&(cnt<=3000000)) //判断是否在20—30秒内
fang_wave(); //显示方波
else if((cnt>3000000)&(cnt<=4000000)) //判断是否在30—40秒内 juchisave(); //显示锯齿波 else cnt=0;
T0IR = 0x01; //清除中断标志
VICVectAddr = 0x00; //通知VIC中断处理结束 } /*
********************************************************************************************************* ** 函数名称 :Timer1_CapInt()
** 函数功能 :定时器1捕获中断服务程序 ** 入口参数 :无 ** 出口参数 :无
********************************************************************************************************* */ /*
*******************************************************************************
15
************************** ** 函数名称 :main()
** 函数功能 :用P0.7控制BEEP,让BEEP鸣叫。 ** 调试说明 :需将跳线JP5和LED短接。
********************************************************************************************************* */
int main (void) {
uint16 i;
uint8 rcv_data;
const double T = (2 * 3.1415926)/1024; //把一个周期分成2048份 PINSEL0 = 0x00005505; // 设置P0[7:4]引脚连接SPIO,P0.0, P0.1引脚连接UART0 PINSEL1=(2<<18)|0x00000000; //设置P0.25连接DAC,设置P0.16,P0.17连接GPIO
UARTMODE uart0_set; uart0_set.datab = 8; uart0_set.stopb = 1; uart0_set.parity = 0; UART0_Init(115200, uart0_set); U0FCR = 0x01; // FIFO使能
MSPI_Init(); // 初始化SPI接口
IO0DIR = HC595_CS|BEEP; //设置74HC595片选为输出, 设置蜂鸣器端口为输出 IO0SET=BEEP; //设置蜂鸣器端口为高电平 for(i=0;i<1024;i++) //循环1024次 {
table[i] = 512*(1+sin(T*i)); //定义table数组 } DACR=(0<<16); //最大定时1US,电流700UA IRQEnable(); //IRQ中断使能 /* 定时器0初始化 */ T0TC=0; //定时器设置为0 T0PR=0; //时钟不分频 T0MCR=0x03; //设置T0MR0匹配后复位T0TC,并产生中断标志 T0MR0=Fpclk/100000; //0.01MS秒钟定时 T0TCR=0x01; //启动定时器
/* 设置定时器0中断IRQ */ VICIntSelect=0x00; //所有中断通道设置为IRQ中断 VICVectCntl0=0x20|0x04; //设置定时器0中断通道分配最高优先级
16
VICVectAddr0=(uint32)IRQ_Timer0; //设置中断服务程序地址 VICIntEnable = 1 << 0x04; //使能定时器0中断 while (1) { if(count==-1) count=9; //当显示0过后,要显示9 if(cnt==9) //判断是否为10秒之内的初始值 {PC_DispChar(4,0x00);PC_DispChar(3,0x00);PC_DispChar(2,0x6d);PC_DispChar(1,0x06);PC_DispChar(0,0x37);} //在仿真LED数码管显示器上显示SIN if(cnt==1000009) //判断是否为10秒与20秒间的初始值 { PC_DispChar(6,0x6d);PC_DispChar(5,0x77);PC_DispChar(4,0x37);PC_DispChar(3,0x1e);PC_DispChar(2,0x06);PC_DispChar(1,0x77);PC_DispChar(0,0x3f);} //在仿真LED数码管显示器上显示SANJIAO if(cnt==2000009) //判断是否为20秒与30秒间的初始值 {PC_DispChar(6,0x00);PC_DispChar(5,0x00);PC_DispChar(4,0x00);
PC_DispChar(3,0x71); PC_DispChar(2,0x77); PC_DispChar(1,0x37); PC_DispChar(0,0x6f);} //在仿真LED数码管显示器上显示FANG
if(cnt==3000009) //判断是否为30秒与40秒间的初始值 {PC_DispChar(6,0x00);PC_DispChar(5,0x00);PC_DispChar(4,0x1E);
PC_DispChar(3,0x3E); PC_DispChar(2,0x39); PC_DispChar(1,0x76); PC_DispChar(0,0x06);} //在仿真LED数码管显示器上显示JUCHI if((cnt%100000)==0) //判断是否到1秒的时间 { if ((IO0PIN & KEY1) == 0) v+=2; //如果KEY1按下,幅值变量V加2 if ((IO0PIN & KEY2) == 0) v-=2; //如果KEY2按下,幅值变量V减少2 if(v>26)v=13; //如果V的值大于26,V的值为13 if(v<2)v=13; //如果V的值小于2,V的值为13 rcv_data = MSPI_SendData(DISP_TAB[count--]); //发送显示倒计时数据 }
if(count==9) IO0CLR=BEEP; //如果秒值为9,蜂鸣器蜂鸣 if(count==8) IO0SET=BEEP; //如果秒值为8,蜂鸣器停止蜂鸣 }
return 0; }
/****************************************************************************/
17
18
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- sceh.cn 版权所有 湘ICP备2023017654号-4
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务