两个编程示例学习DSP定时器与中断系统

前面的学习中介绍了CPU定时器与中断系统,下面借助两个实例回顾下之前的学习内容!

实例1:利用蜂鸣器模拟基本音级

1.1 蜂鸣器的工作原理

蜂鸣器发声原理是电流通过电磁线圈,使电磁线圈产生磁场来驱动振动膜发声的,因此需要一定的电流才能驱动它,单片机 IO 引脚输出的电流较小,单片机输出的 TTL 电平基本上驱动不了蜂鸣器,因此需要增加一个电流放大的电路。实验板通过一个三极管 Q1 来放大驱动蜂鸣器。

1.2 蜂鸣器的分类

蜂鸣器按其是否带有信号源又分为有源和无源两种类型。有源蜂鸣器只需要在其供电端加上额定直流电压,其内部的震荡器就可以产生固定频率的信号,驱动蜂鸣器发出声音。无源蜂鸣器可以理解成与喇叭一样,需要在其供电端上加上高低不断变化的电信号才可以驱动发出声音。对于有源和无源的驱动方式,略有不同,先讲解一下有源蜂鸣器的驱动方法。有源蜂鸣器因为内含有信号源,因此只要加上额定的工作电压就可以发出固定频率的声音。对于无源的蜂鸣器,驱动其发出声音就较为复杂,因为它本身不带信号源,因此,只是通上电源,是不能发出声音的,必须要不断的重复“通电-断电”,才能使其发出声音,我们可以通过编写程序,控制 GPIO口不断的置为高电平—低电平—高电平…,这样蜂鸣器就可以不断的通、断电,从而发出声音。而通电、断电的时间不同,相当于振荡周期的不同,因此又可以得到不同频率的声音。

1.3 蜂鸣器的硬件电路图

从下面的电路图中可以看出,控制蜂鸣器发生的高低电平输入信号接口为GPIO7。通过控制GPIO7开启关闭的时间不同,就可以控制蜂鸣器得到不同频率的声音信号。
在这里插入图片描述在这里插入图片描述

1.4 DSP如何输出组频率

为了让 dsp 发出不同频率的声音,采用定时中断来计算延时时间,只需将定时器预置不同的定时值就可实现不同时间的定时。以标准音高 A 为例: A 的频率 f=440Hz,其对应的周期为: T=1/f=1/440=2272us。
在这里插入图片描述
DSP 控制蜂鸣器的波形图,通过对 GPIO端口 循环的置位、清零来达到输出固定频率波形,相对于 A 音频率 440Hz 如图 T=2272us,那么 t=T/2=2272/2=1136us 所以,我们只要在程序中将 GPIO置为高电平,延时 1136us,再置为低电平,延时 1136us,如此循环,就可以得到440Hz 频率的声音。
在这里插入图片描述

1.5 代码实例
#include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h"   // DSP2833x Examples Include File
/****************端口宏定义*****************/
#define BUZZ_CLK_GENER	GpioDataRegs.GPATOGGLE.bit.GPIO7 = 1;	//蜂鸣器控制IO电平翻转
#define BELL_DIR GpioCtrlRegs.GPADIR.bit.GPIO7                  //定义IO输出方向
#define BELL_DAT GpioDataRegs.GPADAT.bit.GPIO7                  //定义IO寄存器数值
#define DISABLE_TIMER1_INT		IER &= 0xFFFE;          //CPU中断使能标志位清除
#define ENABLE_TIMER1_INT		IER |= M_INT1;          //CPU中断使能标志位使能
#define BUZZ_OFF	 GpioDataRegs.GPACLEAR.bit.GPIO7 = 1;   //IO输出清除
Uint16 Musi[23]=
{		                 //单位 us,不同频率下,蜂鸣器发出不同音调的声音
        0,
        3816,	//L_do
	3496,	//L_re
	3215,	//L_mi
	2865,	//L_fa
	2551,	//L_so
	2272,	//L_la
	2024,	//L_xi
	1912,	//do
	1703,	//re
	1517,	//mi
	1432,	//fa
	1275,	//so
	1136,	//la
	1013,	//xi
	956,	//H_do
	851,	//H_re
	758,	//H_mi
	716,	//H_fa
	638,	//H_so
	568,	//H_la
	506,	//H_xi
	0xFF	//STOP
};
Uint16 Song[]={1,2,3,4,5,6,7}; //乐谱:do,re,mi,fa,so,la,xi

/****************函数声明*******************/ 
void Init_Bell(void);
interrupt void cpu_timer0_isr(void);
void Delay(Uint16 t);
void main(void)
{
	Uint16 addr=0;
	Uint16 k;
	InitSysCtrl();    //  初始化系统控制:
   	BELL_DAT=0;       //设置端口为低电平
   	Init_Bell();     //设置蜂鸣器端口输出  
  	DINT;            // 禁止CPU全局中断
   	InitPieCtrl();   // 初始化PIE控制寄存器到他们的默认状态,即禁止PIE中断及清除所有PIE中断标志 
   	IER = 0x0000;    // 禁止CPU中断和清除所有CPU中断标志 
  	IFR = 0x0000;
   	InitPieVectTable();     //初始化PIE中断向量表,并使其指向中断服务子程序(ISR)
   	EALLOW;                   //解除寄存器保护
   	PieVectTable.TINT0 = &cpu_timer0_isr;// 本例中的中断重新映射到本文件中的中断服务子程序中  
   	EDIS;                                                     // 添加寄存器保护
   	InitCpuTimers();   // 初始化片内外设,本例仅需要初始化CPU定时器
   	ConfigCpuTimer(&CpuTimer0, 150, 1000000);// 配置CPU定时器1每秒发生一次中断
   	StartCpuTimer0();  //开始计时器
   	IER |= M_INT1;     //使能CPU中断线INT1,连接到CPU定时器0的;
   	PieCtrlRegs.PIEIER1.bit.INTx7 = 1;// 使能PIE组1中断7,TINT0中断;
   	EINT;    // 使能全局中断INTM
  	ERTM;   // 使能全局实时中断DBGM
   	for(k=0;k<7;k++) // 步骤 6. 中断控制蜂鸣器开关频率,延时函数定义乐拍,7次循环分别让蜂鸣器响7种乐声:
  	{
        	StopCpuTimer0();					//停止计数
		DISABLE_TIMER1_INT;					//不使能定时器中断
		ConfigCpuTimer(&CpuTimer0, 150, Musi[Song[addr]+14]/2);	//根据音节的频率设置定时时间
		StartCpuTimer0();					//重启定时器
		ENABLE_TIMER1_INT;					//使能定时中断
		Delay(8);						//音乐节拍延时
		StopCpuTimer0();					//停止计数
		DISABLE_TIMER1_INT;					//不使能定时中断
		BUZZ_OFF;						//关闭蜂鸣器
		Delay(2);						//音乐停顿
		addr++;                                                 //连续发出乐谱:do,re,mi,fa,so,la,xi
  	}
	while(1);  
} 

/*-----------------------------------------*/
/*形式参数:void                            */
/*返回值:void				   */
/*函数描述:初始化蜂鸣器端口为输出              */
/*-----------------------------------------*/
void Init_Bell(void)
{
	EALLOW;	   //解除寄存器保护
	BELL_DIR=1;//Bell端口输出
	EDIS;      //寄存器保护
} 
/*------------------------------------------*/
/*形式参数:void                             */
/*返回值:void				    */
/*函数描述:定时器CPU0中断服务子程序            */
/*------------------------------------------*/ 

interrupt void cpu_timer0_isr(void)
{
   CpuTimer0.InterruptCount++;
   BUZZ_CLK_GENER;     //GPIO口输出电平翻转
   PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;    //PIEACK标志位置位,告诉PIE可以接受本组其他中断处理
}

void Delay(Uint16 t)			     //延时函数
{
	Uint32 i=0;
	Uint32 gain = 300000;	
	Uint32 base=0;								
	base=gain*t; 															
	for(i=0;i<=base;i++);
}

实例2:利用定时器中断实现LED灯变频闪烁

实例比较简单,直接上源码。

#include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h"   // DSP2833x Examples Include File
/***************************************************************************************************
**Description  ** 全局变量定义
***************************************************************************************************/
volatile unsigned int timer_int_cnt;
interrupt void cpu_timer0_isr(void);
interrupt void cpu_timer1_isr(void);
interrupt void cpu_timer2_isr(void);
void Gpio_select(void);
void main(void)
{
   	InitSysCtrl();   //  初始化系统控制,包括看门狗、PLL、外部时钟
   	Gpio_select();	 // 初始化使用到的GPIO口;
   	DINT;            //禁止CPU中断
   	InitPieCtrl();   //初始化PIE控制寄存器到他们的默认状态,即禁止PIE中断及清除所有PIE中断标志
   	IER = 0x0000;    // 禁止CPU中断
   	IFR = 0x0000;    // 清除所有CPU中断标志
   	InitPieVectTable();//初始化PIE中断向量表,并使其指向中断服务子程序(ISR)
   	EALLOW;            //解除寄存器保护
   	PieVectTable.TINT0 = &cpu_timer0_isr;         //PIE组1第7个中断为定时器Timer0(外设中断)
   	PieVectTable.XINT13 = &cpu_timer1_isr;        //TINT13为CPU定时器中断Timer1(内部中断源)
   	PieVectTable.TINT2 = &cpu_timer2_isr;         //TINT2为CPU定时器中断Timer2(内部中断源)
   	EDIS;              //寄存器保护
   	InitCpuTimers();   // 初始化CPU定时器

#if (CPU_FRQ_150MHZ)      // 配置CPU定时器 0, 1, and 2 中断周期,150MHzCPU频率, 周期单位为us;
   	ConfigCpuTimer(&CpuTimer0, 150, 100000);    //Timer0定时器中断周期为0.1s
   	ConfigCpuTimer(&CpuTimer1, 150, 200000);    //Timer1定时器中断周期为0.2s
   	ConfigCpuTimer(&CpuTimer2, 150, 400000);    //Timer2定时器中断周期为0.4s
#endif
   	CpuTimer0Regs.TCR.all = 0x4001; // 设置TIE = 1,开启定时器0中断
  	CpuTimer1Regs.TCR.all = 0x0001; // 设置TIE = 0,关闭定时器1中断
   	CpuTimer2Regs.TCR.all = 0x0001; // 设置TIE = 0,关闭定时器2中断
   	IER |= M_INT1;                  //使能CPU中断线INT1
   	IER |= M_INT13;                 //使能CPU中断线INT13
   	IER |= M_INT14;                 //使能CPU中断线INT14
   	PieCtrlRegs.PIEIER1.bit.INTx7 = 1;    //使能PIE组1第七位的使能标志位
   	EINT;     // 使能全局中断INTM
   	ERTM;     // 使能全局实时中断DBGM
	timer_int_cnt = 0;
   	for(;;);
}
interrupt void cpu_timer0_isr(void)       //Timer0中断处理函数
{
   	CpuTimer0.InterruptCount++;
   	EALLOW;
    	if(timer_int_cnt++ >= 12) 
    	{
        	timer_int_cnt = 0;
        	CpuTimer0Regs.TCR.all = 0x0001;           // 设置TIE = 0,关闭定时器0中断
        	CpuTimer1Regs.TCR.all = 0x4001;           // 设置TIE = 1,开启定时器1中断
        	CpuTimer2Regs.TCR.all = 0x0001;           // 设置TIE = 0,关闭定时器2中断
    	}

	GpioDataRegs.GPBTOGGLE.all =0x30000000; 
    	GpioDataRegs.GPCTOGGLE.all =0x00000007;
   	PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;    //PIEACK标志位置位,告诉PIE可以接受本组其他中断处理
   	EDIS;
}

interrupt void cpu_timer1_isr(void)     //Timer1中断处理函数
{
   	CpuTimer1.InterruptCount++;
   	EALLOW;
   	if( timer_int_cnt++ >= 12) 
    	{
       	 	timer_int_cnt = 0;
        	CpuTimer0Regs.TCR.all = 0x0001;          // 设置TIE = 0,关闭定时器0中断
        	CpuTimer1Regs.TCR.all = 0x0001;          // 设置TIE = 0,关闭定时器1中断
        	CpuTimer2Regs.TCR.all = 0x4001;          // 设置TIE = 1,开启定时器2中断
    	}
    	GpioDataRegs.GPBTOGGLE.all =0x30000000;          //对应的GPIO高低电平翻转
    	GpioDataRegs.GPCTOGGLE.all =0x00000007;          //对应的GPIO高低电平翻转
   	// The CPU acknowledges the interrupt.
   	EDIS;
}
interrupt void cpu_timer2_isr(void)      //Timer2中断处理函数
{  
   	CpuTimer2.InterruptCount++;
    	EALLOW;
    	if( timer_int_cnt++ >= 12) 
    	{
        	timer_int_cnt = 0;
        	CpuTimer0Regs.TCR.all = 0x4001;          // 设置TIE = 1,开启定时器0中断
        	CpuTimer1Regs.TCR.all = 0x0001;          // 设置TIE = 0,关闭定时器1中断
        	CpuTimer2Regs.TCR.all = 0x0001;          // 设置TIE = 0,关闭定时器2中断
    	}
    	GpioDataRegs.GPBTOGGLE.all =0x30000000; 
    	GpioDataRegs.GPCTOGGLE.all =0x00000007;
   	EDIS;
}
void Gpio_select(void)
{
    	EALLOW;
	GpioCtrlRegs.GPAMUX1.all = 0x00000000;  // 对应的引脚复用成IO
	GpioCtrlRegs.GPAMUX2.all = 0x00000000;  // 对应的引脚复用成IO
	GpioCtrlRegs.GPBMUX1.all = 0x00000000;  // 对应的引脚复用成IO
    	GpioCtrlRegs.GPBMUX2.all = 0x00000000;  // 对应的引脚复用成IO
	GpioCtrlRegs.GPCMUX1.all = 0x00000000;  // 对应的引脚复用成IO
	GpioCtrlRegs.GPCMUX2.all = 0x00000000;  // 对应的引脚复用成IO
    	GpioCtrlRegs.GPADIR.all = 0xFFFFFFFF;    // 对应的引脚用作输出
    	GpioCtrlRegs.GPBDIR.all = 0xFFFFFFFF;   // 对应的引脚用作输出
    	GpioCtrlRegs.GPCDIR.all = 0xFFFFFFFF;   // 对应的引脚用作输出
   	GpioDataRegs.GPBDAT.all    =0x30000000;  // 设置对应引脚的高低电平
   	GpioDataRegs.GPCDAT.all    =0x00000007;  // 设置对应引脚的高低电平
    	EDIS;
}    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值