[资料分享] LPC2000系列ARM芯片的电子琴的设计

Aguilera   2019-9-3 22:19 楼主

1.用LPC2000系列ARM芯片设计电子琴,用proteus软件仿真。
2.按下不同的按键,扬声器能够发出不同的音调。
3.用PWM控制扬声器可以实现音调的条件。

 

通过编程,利用按键去控制扬声器的发声。
    通过小组讨论分析,结合设计电路性能指标、器件的性价比,本设计电路选择方案二。
  • 硬件设计与介绍
嵌入式的定义:
从技术的角度定义:以应用为中心、以计算机技术为基础、软件硬件可裁剪、适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。
    从系统的角度定义:嵌入式系统是设计完成复杂功能的硬件和软件,并使其紧密耦合在一起的计算机系统。术语嵌入式反映了这些系统通常是更大系统中的一个完整的部分,称为嵌入的系统。嵌入的系统中可以共存多个嵌入式系统。
     3.1 213X系列最小系统板介绍:
LPC2131/2132/2138 是基于一个支持实时仿真和嵌入式跟踪的32/16ARM7TDMI-STM CPU 的微控制器,并带有32kB、64kB、512 kB 的嵌入的高速Flash 存储器。128 位宽度的存储器接口和独特的加速结构使32 位代码能够在最大时钟速率下运行。对代码规模有严格控制的应用可使用16 位Thumb模式将代码规模降低超过30%,而性能的损失却很小。
较小的封装和极低的功耗使 LPC2131/2132/2138 可理想地用于小型系统中,如访问控制和POS 机。宽范围的串行通信接口和片内8/16/32kB的SRAM使LPC2131/2132/2138 非常适用于通信网关、协议转换器、软modem、声音辨别和低端成像,为它们提供巨大的缓冲区空间和强大的处理功能。多个32位定时器、1个或2 个10 位8 路ADC、10 位DAC、PWM 通道和47个GPIO 以及多达9个边沿或电平触发的外部中断使它们特别适用于工业控制和医疗系统。
主要特性如下:
(1)16/32位ARM7TDMI-S核,超小LQFP64封装。  ??
(2)8/16/32kB的片内静态RAM和32/64/128/256/512kB的片内Flash程序存储器。128位宽度接口/加速器可实现高达60MHz工作频率。  ??
(3)通过片内boot装载程序实现在系统编程/在应用编程(ISP/IAP)。单个Flash扇区或整片擦除时间 为400ms。256字节行编程时间为1ms。  
(4)EmbeddedICE RT和嵌入式跟踪接口通过片内RealMonitor软件对代码进行实时调试和高速跟踪。 ??
(5)1个(LPC2131/32)或2个(LPC2134/36/38)8路10位的A/D转换器,共提供16路模拟输入,每个通道的转换时间低至2.44us。  ??
(6)1个10位的D/A转换器,可产生不同的模拟输出。(LPC2132/34/36/38)  ?? (7)2个32位定时器/外部事件计数器(带4路捕获和4路比较通道)、PWM单元(6路输出)和看门狗。 
(8)低功耗实时时钟具有独立的电源和特定的32kHz时钟输入。 
(9)多个串行接口,包括2个16C550工业标准UART、2个高速I2C总线(400 kbit/s)、SPI和具有缓冲作用和数据长度可变功能的SSP。
(10)向量中断控制器。可配置优先级和向量地址。  
(11)小型的LQFP64封装上包含多达47个通用I/O口(可承受5V电压)。 ?? (12)多达9个边沿或电平触发的外部中断管脚。  
(13)通过片内PLL(100us的设置时间)可实现最大为60MHz的CPU操作频率。  
(14)片内集成振荡器与外部晶体的操作频率范围为1~30 MHz,与外部振荡器的操作频率范围高达 50MHz。  
(15)低功耗模式:空闲和掉电。  
(16)可通过个别使能/禁止外部功能和外围时钟分频来优化功耗。 
(17)通过外部中断或BOD将处理器从掉电模式中唤醒。 
(18)单电源,具有上电复位(POR)和掉电检测(BOD)电路。 
(19)CPU操作电压范围:3.0V~3.6 V (3.3 V± 10﹪),I/O口可承受5V的电压。

3.2最小系统板结构

    LPC2131/2132/2138 包含一个支持仿真的ARM7TDMI-S CPU、与片内存储器控制器接口的ARM7 局部总线、与中断控制器接口的AMBA 高性能总线(AHB)和连接片内外设功能的VLSI 外设总线(VPB,ARMAMBA 总线的兼容超集)。LPC2131/2132/2138 将ARM7TDMI-S 配置为小端(little-endian)字节顺序。AHB 外设分配了2M 字节的地址范围,它位于4G 字节ARM 存储器空间的最顶端。每个AHB 外设都分配了16k 字节的地址空间。LPC2131/2132/2138 的外设功能(中断控制器除外)都连接到VPB 总线。AHB到VPB 的桥将VPB 总线与AHB 总线相连。VPB 外设也分配了2M 字节的地址范围,从3.5GB 地址点开始。每个VPB 外设在VPB 地址空间内都分配了16k 字节地址空间。
片内外设与器件管脚的连接由管脚连接模块控制。该模块必须由软件进行控制以符合外设功能与管脚在特定应用中的需求。

3.3 片内FLASH程序储存器

LPC2131/2132/2138 分别含有32kB、64kB 和512kB 的FLASH 存储器系统。该存储器可用作代码和数据的存储。对FLASH 存储器的编程可通过几种方法来实现:通过内置的串行JTAG 接口,通过在系统编程(ISP)和UART0,或通过在应用编程(IAP)。使用在应用编程的应用程序也可以在应用程序运行时对FLAH 进行擦除和/或编程,这样就为数据存储和现场固件的升级都带来了极大的灵活性。如果LPC2131/2132/2138 使用了片内引导装载程序(bootloader),32/64/512kB 的Flash 存储器就可用来存放用户代码。
LPC2131/2132/2138 的Flash 存储器至少可擦除/编程10,000 次,保存数据的时间长达10 年。

3.4 片内静态RAM

片内静态RAM(SRAM)可用作代码和/或数据的存储,支持8 位、16 位和32 位的访问。LPC2131/2132/2138 含有8/16/32kB 的静态RAM。
LPC2131/2132/2138 SRAM 是一个字节寻址的存储器。对存储器进行字和半字访问时将忽略地址对准,访问被寻址的自然对准值(因此,对存储器进行字访问时将忽略地址位0 和1,半字访问时将忽略地址位0)。
因此,有效的读写操作要求半字数据访问的地址线0 为0(地址以0、2、4、6、8、A、C 和E 结尾),字数据访问的地址线0 和1 都为0(地址以0、4、8 和C 结尾)。该原则同样用于片外和片内存储器。
SRAM 控制器包含一个回写缓冲区,它用于防止CPU 在连续的写操作时停止运行。回写缓冲区总是保存着软件发送到SRAM 的最后一个字节。该数据只有在软件请求下一次写操作时才写入SRAM(数据只有在软件执行另外一次写操作时被写入SRAM)。如果发生芯片复位,实际的SRAM 内容将不会反映最近一次的写请求(即:在一次“热”芯片复位后,SRAM 不会反映最后一次写入的内容)。任何在复位后检查SRAM 内容的程序都必须注意这一点。通过对一个单元执行两次相同的写操作可保证复位后数据的写入。或者,也可通过在进入空闲或掉电模式前执行虚写(dummy write)操作来保证最后的数据在复位后被真正写入到SRAM。

3.5 存储器映射概念和操作方式

LPC2131/2132/2138 的基本的概念是:每个存储器组在存储器映射中都有一个“物理上的”位置。它是一个地址范围,该范围内可写入程序代码。每一个存储器空间的容量都永久固定在同一个位置,这样就不需要将代码设计成在不同地址范围内运行。
由于ARM7 处理器上的中断向量位置(地址0x0000 0000~0x0000 001C,见表2),Boot Block 和SRAM空间的一小部分需要重新映射来实现在不同操作模式下对中断的使用,见表1。中断的重新映射通过存储器映射控制特性来实现,详见系统控制模块一节。
表1:LPC2131/2132/2138 存储器映射模式
模式
激活
用途
Boot装载程序模式
由任何复位硬件激活
在任何复位后都会执行 Boot 装载程序。Boot Block 中断向量映射到存储器的底部以允许处理异常并在Boot 装载过程中使用中断。
用户Flash模式
由Boot代码软件激活
当在存储器中识别了一个有效的用户程序标识并且Boot 装载操作未被执行时,由Boot 装载程序启动。中断向量没有重新映射,它位于Flash 存储器的底部。
用户RAM模式
由用户程序软件激活
由用户程序激活。中断向量重新映射到静态 RAM 的底部。

3.6 系统控制模块

系统控制模块功能汇总:
系统控制模块包括几个系统特性和控制寄存器,这些寄存器具有众多与特定外设器件无关的功能。
1、晶体振荡器
2、外部中断输入
3、存储器映射控制
4、PLL
5、功率控制
6、复位
7、VPB 分频器
8、唤醒定时器
每种类型的功能都有其自身的寄存器,不需要的位则定义为保留位。为了满足将来扩展的需要,无关/的功能不共用相同的寄存器地址。
表2:系统控制模块功能相关的管脚
管脚名称
管脚方向
管脚描述
X1
输入
晶振输入--振荡器和内部时钟发生器电路的输入
X2
输出
晶振输出--振荡器放大器的输出
EINT0
输入
外部中断输入0--低有效的通用中断输入。该管脚可用于将处理器从空闲或掉电模式中唤醒。
P0.1和P0.16可用作EINT0 功能。
EINT1
输入
外部中断输入1--见上面的EINT0 描述。
P0.3 和P0.14可用作EINT1 功能。
复位后管脚 P0.14上立即出现的低电平被看作是一个启动ISP 命令处理器的外部硬件请求
EINT2
输入
外部中断输入2--见上面的EINT0 描述。
P0.7 和P0.15 可用作EINT2 功能。
EINT3
输入
外部中断输入3--见上面的EINT0 描述。
P0.9,P0.20和P0.30可用作EINT3 功能。
RESET
输入
外部复位输入--该管脚上的低电平将芯片复位,使I/O 口和外设恢复其默认状态,并使处理器从地址0 开始执行程序。
                      图3.1 LPC2138管脚排列图
  3.7 行列式键盘工作原理
ARM嵌入式系统使用常用的行列式键盘电路,此电路的优点是比较节省I/0口线,并且接口简单。它的工作模式如下图所示。它的行线与按键的一个引脚相连,列线与按键的另一个引脚相连。平时列线被置成低电平,没有按键被按下时,行线保持高电平,而有按键被按下时,行线被拉成低电平。如图3.2。



 

图3.2 键盘扫描模式
  3.8 键盘识别原理
对于常规的按键识别过程一般分为以下几步:
(1)用IF语句判断按键是否按下。
(2)调用延时函数延时去除按键抖动。
(3)再用IF语句判断是否真的按下。
(4)是真的按下,则执行按键处理程序。
(5)用WHILE语句等待按键释放。
为了考虑提高CPU的效率和充分利用CPU的资源等因素,可将第2步和第5步的延时和等待过程用其他方式代替。
  3.9键盘电路介绍
为了实现电子琴的输入,需要扩展键盘以作为控制输入。系统采用LPC2138的P0.8--P0.13端口引脚作为2X4矩阵键盘的扩展接口,电路原理图如图3.3所示。
                       图 3.3 键盘电路

 

在扩展键盘时需要解决两个问题,一是键盘的抖动,二是多键同时按下。键盘的去抖动可通过软件的适当延时实现,即在读入端口P0.8~P0.11后,适当延时一段时间,再读入端口P0.12~P0.13,两次比较后确定按键是否真按得下。多键同时按下也可通过软件设计屏蔽多按下的键,对于同一列的键同时按下,可以只取键值最小的键,屏蔽值大的键,或反之。对于不同列的键,可以将P0.12~P0.13设置优先级,如P0.12最高,P0.13最低,或反之。这样,只取优先级高的键,屏蔽优先级低的键。
在ARM中,必须将管脚置为GPIO口后才能将管脚作为I/O口的功能来使用,由于在I/O的初始化中已经将用到的管脚设置为GPIO口,固可以将管脚作为I/O口的功能来使用。具体方法如下:
先将P0.8-P0.11这4列端口设置为输入管脚并且置为低电平,然后将P0.12-P0.13这2行端口设置为输出管脚并且置为高电平,通过判断是否有按键按下,如果有按键按下则可以首先确定2行端口的代码,接着再将4列端口设置为输出管脚并且置为高电平,将2行端口设置为输入管脚并且置为低电平,以此来决定4列端口的代码,然后再讲4列端口代码和2行端口代码按照2行为高4位,4列为低4位的顺序排成一个8位代码。
3.10 蜂鸣器驱动电路分析
   蜂鸣器驱动电路分析如下:
   蜂鸣器:发声元件,在其两端施加直流电压(有源蜂鸣器)或者方波(无源蜂鸣器)就可以发声,其主要参数是外形尺寸、发声方向、工作电压、工作频率、工作电流、驱动方式(直流/方波)等。这些都可以根据需要来选择。
   续流二极管:蜂鸣器本质上是一个感性元件,其电流不能瞬变,因此必须有一个续流二极管提供续流。否则,在蜂鸣器两端会产生几十伏的尖峰电压,可能损坏驱动三极管,并干扰整个电路系统的其它部分。
   三极管驱动蜂鸣器电路:三极管Q1起开关作用,其基极的高电平使三极管饱和导通,使蜂鸣器发声;而基极低电平则使三极管关闭,蜂鸣器停止发声。如图3.4。

 

                        图3.4实际选用驱动放大电路
 

 

  3.11 整体电路图
       如图3.5所示。
                      图3.5 硬件设计电路整体图
  • 软件设计
   1.程序流程图如图4.1所示。
                      图4.1程序流程图
  2.软件设计程序代码如下:
  1. /*******************************************************************************
  2. *File: Main.c
  3. *功能: 使用PWM6输出PWM信号,通过滤波电路实现DAC转换.由按键控制PWM占空比,每按一次
  4. *      按键将会改变一次PWM的占空比,使蜂鸣器发出不同的音调。
  5. *******************************************************************************/
  6. #include "config.h"
  7. #define   KEY1   0x00004000        /*P0.14引脚连接KEY1*/
  8. #define   KEY2   0x00000400        /*P0.10引脚连接KEY2*/
  9. #define   KEY3   0x00000800        /*P0.11引脚连接KEY3*/
  10. #define   KEY4   0x00001000        /*P0.12引脚连接KEY4*/
  11. #define   KEY5   0x00002000        /*P0.13引脚连接KEY5*/
  12. #define   KEY6   0x00008000        /*P0.15引脚连接KEY6*/
  13. #define   KEY7   0x00010000        /*P0.16引脚连接KEY7*/
  14. #define   KEY8   0x00020000        /*P0.17引脚连接KEY8*/
  15.  
  16. /*******************************************************************************
  17. *名称: WaitKey()
  18. *功能: 等待一个有效按键,有去抖功能
  19. *******************************************************************************/
  20. /*void WaitKey(void)
  21. { uint32 i;
  22.  
  23.   while(1)
  24.   { while((IOPIN&KEY1)!=0);                 //等待KEY1键按下
  25.     for(i=0;i<50;i++);                      //延时去抖
  26.     if((IOPIN&KEY1)==0)break;
  27.   }
  28.     while((IOPIN&KEY1)==0);                   //等待KEY1键放开
  29. }*/
  30. void TargetInit(void);
  31. /*******************************************************************************
  32. *名称: main()
  33. *功能: 使用PWM6输出占空比可调的PWM波形
  34. *******************************************************************************/
  35. int main(void)
  36. { uint32  pwmdata;                        //PWM占空比控制变量
  37.   int i;
  38.   PINSEL0=0x00080000;                     //设置PWM6连接到P0.9引脚
  39.   PINSEL1=0x00000000;                     //其他引脚设置为GPIO
  40.   TargetInit();                           //PWM初始化
  41.   pwmdata=1382;
  42.   while(1)
  43.   {  PWMMR0=2765;                         //设置PWM周期
  44.      PWMMR6=pwmdata;                      //设置PWM占空比
  45.      PWMLER=0x41;                         //PWMMR0,PWMMR6锁存,更新PWM占空比
  46.     // WaitKey();                           //等待按键
  47.  
  48.     if(KEY1==0)
  49.                    { while((IOPIN&KEY1)!=0);                 //等待KEY1键按下
  50.                   for(i=0;i<50;i++);                      //延时去抖
  51.                   if((IOPIN&KEY1)==0)break;
  52.                    }
  53.                   while((IOPIN&KEY1)==0);                   //等待KEY1键放开
  54.                    pwmdata=100;                        //改变PWM占空比控制变量
  55.  
  56.     if(KEY2==0)
  57.                    { while((IOPIN&KEY2)!=0);                 //等待KEY2键按下
  58.                   for(i=0;i<50;i++);                      //延时去抖
  59.                   if((IOPIN&KEY2)==0)break;
  60.                    }
  61.                   while((IOPIN&KEY2)==0);                   //等待KEY2键放开
  62.                    pwmdata=300;                        //改变PWM占空比控制变量
  63.                   
  64.     if(KEY3==0)
  65.                    { while((IOPIN&KEY3)!=0);                 //等待KEY3键按下
  66.                   for(i=0;i<50;i++);                      //延时去抖
  67.                   if((IOPIN&KEY3)==0)break;
  68.                    }
  69.                   while((IOPIN&KEY3)==0);                   //等待KEY3键放开
  70.                    pwmdata=500;                        //改变PWM占空比控制变量
  71.                   
  72.     if(KEY4==0)
  73.                    { while((IOPIN&KEY4)!=0);                 //等待KEY4键按下
  74.                   for(i=0;i<50;i++);                      //延时去抖
  75.                   if((IOPIN&KEY4)==0)break;
  76.                    }
  77.                   while((IOPIN&KEY4)==0);                   //等待KEY4键放开
  78.                    pwmdata=700;                        //改变PWM占空比控制变量  
  79.                   
  80.     if(KEY5==0)
  81.                    { while((IOPIN&KEY5)!=0);                 //等待KEY5键按下
  82.                   for(i=0;i<50;i++);                      //延时去抖
  83.                   if((IOPIN&KEY5)==0)break;
  84.                    }
  85.                   while((IOPIN&KEY5)==0);                   //等待KEY5键放开
  86.                    pwmdata=900;                        //改变PWM占空比控制变量
  87.                   
  88.               if(KEY6==0)
  89.                    { while((IOPIN&KEY6)!=0);                 //等待KEY6键按下
  90.                   for(i=0;i<50;i++);                      //延时去抖
  91.                   if((IOPIN&KEY6)==0)break;
  92.                    }
  93.                   while((IOPIN&KEY6)==0);                   //等待KEY6键放开
  94.                    pwmdata=1100;                        //改变PWM占空比控制变量 
  95.                   
  96.     if(KEY7==0)
  97.                    { while((IOPIN&KEY7)!=0);                 //等待KEY7键按下
  98.                   for(i=0;i<50;i++);                      //延时去抖
  99.                   if((IOPIN&KEY7)==0)break;
  100.                    }
  101.                   while((IOPIN&KEY7)==0);                   //等待KEY7键放开
  102.                    pwmdata=1300;                        //改变PWM占空比控制变量   
  103.                   
  104.                   
  105.     if(KEY8==0)
  106.                    { while((IOPIN&KEY8)!=0);                 //等待KEY8键按下
  107.                   for(i=0;i<50;i++);                      //延时去抖
  108.                   if((IOPIN&KEY8)==0)break;
  109.                    }
  110.                   while((IOPIN&KEY8)==0);                   //等待KEY8键放开
  111.                    pwmdata=1500;                        //改变PWM占空比控制变量
  112.                        
  113.      if(pwmdata>=2764)pwmdata=0;
  114.   }
  115.   return(0);
  116. }
  117. //PWM初始化函数
  118.   void TargetInit(void)
  119. {
  120. PWMPR=0x00;                      //不分频
  121. PWMMCR=0x02;                     //设置PWMMR0匹配
  122.     PWMMR0=2765;                     //设置PWM周期
  123. PWMMR6=1382;                     //设置PWM占空比   
  124. PWMLER=0x41;                     //PWMMR0,PWMMR6锁存                                               PWMPCR=0x4000;                       //允许PWM单边输出 
  125.     PWMTCR=0x09;                     //PWM使能
  126. }
复制代码

  • 系统的仿真与调试
   将编译好的十六制文件下载到proteus中的ARM芯片中。
    第一次用软件调试时,没有任何现象,检查了好久终于发现了原来是有一个电源没有设置数值,也没有标明电源的极性,将其改为+3.3V时现象就出现了。
依次按下KEY1-KEY,依次发出不同音调的声音,按下复位键系统回归到初始状态。
    图5.1 为硬件设计电路整体图。

 

                          图5.1 硬件设计电路整体图
  • 设计总结
此次嵌入式设计的主要内容:基于LPC2000系列的高级电子琴设计。它的主要功能是:实现不同频率的音调输出。因此要涉及到蜂鸣器的驱动电路,按键的扫描程序,最小系统电路的设计。
刚开始时拿到这个设计的题目是还有点不知所措,但通过上网查阅LPC213X系列最小系统板的相关资料,学会了用proteus进行ARM仿真,查找了一些以应用嵌入式ARM的仿真实例,分析各个实例的工作原理,将各个实例的有用模块综合运用得到本实训基于嵌入式ARM的高级电子琴设计的原理图,该图主要包括三个模块:2*4键盘、PWM脉冲输出、功率放大电路。控制LPC213X系列最小系统板的P0.9口输出PWM脉冲发出不同频率使蜂鸣器发出不同的声音,P0.9口外接功放电路连接蜂鸣器发声。按键输入功能有8个输入故最终确定采用2*4的矩阵键盘作为电子密码锁的键盘控制。经过网上收集资料与同学之间的讨论,终于明白了键盘扫描的工作原理,和51单片机一样都是利用动态扫描原理最终实现了键盘输入的功能。依靠程序完成大部分的功能,所以程序的调试是重中之重,当然前提是能够编写并会修改程序。
    此次设计总的来说进行的还顺利,这是小组成员团结付出的结果,当然,在此期间指导老师也为我们提供了巨大的帮助,在此表示深深的感谢!在此期间也学到了许多,特别是对软件的应用,如proteus,ADS1.2,AXD,加强了理论与实践的联系。

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复