第一个程序,让你的板子唱国歌(败笔)

虽然是败笔,但是文中基本上介绍了一个小应用实现及问题分析的全过程,希望能够对你有帮助,大胆贴出!毕竟这篇文章写了好久。。。额,写文章的人伤不起啊伤不起。。。


学生时代总会有这么一句笑话:“XXX!去,给我蹲政教处门口唱国歌!”

      一直在思索第一个例子用什么,才能引起学生的兴趣,点亮板子的LED?貌似很无聊啊,你也不能拿着给同学炫耀,毫无吸引力,那么就索性用这个例子吧,顺便也抒发一下我对祖国的热爱。让我们的板子唱起国歌来!

      前记:在这篇文章之前,我并没有做过类似的实验,所以我们站在同一个起跑线上,千万不要抱怨别人比你厉害是因为他比你聪明。如果试验成功,板子真的这么唱歌了,像我这么笨的人都做到了,你没有理由做不到,这篇文章让你找回自信。

      首先要贴出来一篇参考文章,是基于C51的唱国歌的例子,做人要实在,我不想把它说成是我原创的,因为我也没学过C51,呵呵,但是我会举一反三。因为ARM板裸奔跟写C51的程序差不多,虽然扼杀了它的处理能力(本该是跑系统的),但是要练习对硬件的操控能力和做接口实验,这些是必须的。下边是文章内容:

蜂鸣器使用在很多的场合,他一般用来发出报警或者提示的声音,是一种常用的电子器件,这里我给大家 简单的介绍一下用单片机驱动蜂鸣器的方法, 蜂鸣器有二种 1.本身带有驱动电路, 5v,9v,12v 超电压使用, 分 声音沙哑失真。2.象 call 机,喇叭一样,用软件驱动。频率控制音调,时间控制音量大小,第一种蜂鸣器 一般都有一个固定的频率参数也就是他他发出的声音是不能变化的,就象食堂用的打卡器一样,卡一贴近 就发出都的一声。第 2 种就不同了用单片机驱动第 2 种蜂鸣器后还可以使他演 奏出美妙的音乐,我们只需 要用简单的程序就可以控制单蜂鸣器所奏的频率,也就控制了音调。
 c51程序实例: 单片机驱动蜂鸣器演奏中华人民共和国国歌的前 4 节的 c51 程序: 

#include <REG52.h> 
sbit BUZ=P2^6; //蜂鸣器接单片机的p2.6 电路很简单。
 unsigned int hzs[]={131,147,165,175,196,220,247,262,294,330,349,392,440,494,523,587,659,698,784,880,988,1047,1175,131 9,1397,1568,1760,1976};//标准音调频率 
char dots[]={8,28,10,12,12,13,28,28,12,28,10,28,8,12,12,12,10,28,28,8,28,5,5,5,5,5,5,8,'#'};//频率控制数组
 void delay(unsigned int u) //延时 
{ 
while(u--); 
} 
void play_hz(unsigned int u) { 
unsigned int i=u; 
while(i--){
 		BUZ=0; 
BUZ=1;
 delay(18432/u-24); 
} 
} 
void play_sound(int i) {
 if(i<28) 
play_hz(hzs[i-1]); 
else 
delay(500); } 
void main(void) //主程序开始 
{ 
while(1){
 int i=0; 
while(dots[i]!='#') 
play_sound(dots[i++]); 
delay(20000);
 } 
} //播放音乐 
音调与频率的关系: 
C:261.6256
D:293.6648 
E:329.6276 
F:349.2282 
G:391.9954 
A:440 
B:493.8833 
每个 8 度频率加倍,如 A 的高 8 度是 880HZ,再高 8 度是 1760HZ。 反之,A 的低 8 度是 220HZ,再低 8 度是 110HZ。

完文章,我们来做ARM下的实现:

我想当你看完文章,应该有些思路了吧,不知道我们的思路一样不一样,也不知道这个实验可否成功,让我们一起去探索一下》》》》》》

      我的思路是这样的:蜂鸣器的控制应该和LED的控制是一样的,根据电路设计,在对应的控制寄存器中的对应控制位写1(或者0)他就唱,相反,他就不唱。而不同的音调就是通过频率来控制的,而频率就是一个动作周期性变化的次数,上边的程序已经写得非常到位,简洁有力,通过while循环和时延控制频率。理论上我们只用作少量改动就可以使用。而这些改动就要看我们自己的板子的设计了,我的是TQ2440,虽不知你的是不是,但是只要你可以在你的板子上迁移成功,证明你已经提升了,OK,here we go。


      先看一下TQ2440 的 buzzer相关的电路(在TQ2440底板原理图里):


第一个程序,让你的板子唱国歌(败笔)_第1张图片


我们看到了只有一条接入的控制线  TOUT0 ,让我们到S3C2440的针脚中找找它去》》》》》》(在TQ2440_V2核心板原理图.pdf中,直接ctrl+F搜索一下)


第一个程序,让你的板子唱国歌(败笔)_第2张图片


我们看到TOUT0和GPB0是共用一个针脚的,就是可以通过GPIO接口来控制这个针脚输出高低电平,从而控制Buzzer的声响和声调,咱们现在就去S3C2440的datasheet里探寻一下这个针脚的控制信息》》》》》


第一个程序,让你的板子唱国歌(败笔)_第3张图片


图中我标出了一些信息,这里有GPBCON,故名思意,CON就是configuration的意思,起到针脚的配置作用,这里还有GPBCON的地址信息。GPBDAT 就是用来控制针脚输出的高低电平的。而在最下边GPB0占用的只是GPBCON的0位和1位[1:0],而当这两位是10时,该阵脚就是TOUT0。Ok,基本上明白了吧,我们以上边的代码为基础,进行简单更改,下边是我改后的代码:

主要逻辑:beep.c

#define GPBCON (*(volatile unsigned long*)0x56000010)
#define GPBDAT (*(volatile unsigned long*)0x56000014)
/* 标准音调频率 */
unsigned int hzs[]={131,147,165,175,1 96,220,247,262,294,330,349,392,440,494,523,587,659,698,784,880,988,1047,1175,1319,1397,1568,1760,1976};
/*频率控制数组*/
char dots[]={8,28,10,12,12,13,28,28,12,28,10,28,8,12,12,12,10,28,28,8,28,5,5,5,5,5,5,8,'#'};
		
/*延时*/
void delay(unsigned int u) 
{ 
	while(u--);
}

void play_hz(unsigned int u)
{ 
	unsigned int i=u;
	while(i--){
		
 		GPBDAT &= ~(1);
		GPBDAT &= ~(0);
		
 		delay(18432/u-24);
	}
}

void play_sound(int i)
{
 	if(i<28) 
		play_hz(hzs[i-1]);
	else 
		delay(500);
}

int main(){
	GPBCON = (1<<1);			
	while(1){
 		int i=0; 
		while(dots[i]!='#')
			play_sound(dots[i++]);
		delay(20000);
 }	
	return 0;
}

hard_init.S  — 完成硬件初始化,关闭看门狗、初始化堆栈、调用main等的工作:

/*这个文件是写裸机程序都要用到的,所以可以保留,以后的裸机程序都可以专注在C语言部分了,不过我没打算写多少裸机实验,因为我们的目标是Linux*/


@*******************************
@	File:hard_init.S
@ 功能:通过该程序转入C程序
@
@	author:Jun		2011-7-20
@*******************************

.text
.global	_start
_start:
	ldr	r0,=0x53000000		@	WATCHDOG 寄存器地址
	mov	r1,#0x0
	str	r1,[r0]
	
	ldr	sp,=1024*4				@	设置堆栈,注意不能大于4K,因为现在可用的内存只有4K,是片内的4K SRAM
	
	bl	main
	
halt_loop:
	b	halt_loop

Makefile   /*Makefile是参照的嵌入式Linux应用开发完全手册的编译选项,带有反编译的汇编文件,有助于调试和分析*/


beemp.bin:hard_init.S beemp.c
	arm-linux-gcc -g -c -o hard_init.o hard_init.S
	arm-linux-gcc -g -c -o beemp.o beemp.c
	arm-linux-ld -Ttext 0x0000000 -g hard_init.o beemp.o -o beemp_elf
	arm-linux-objcopy -O binary -S beemp_elf beemp.bin
	arm-linux-objdump -D -m arm beemp_elf > beemp.dis
clean:
	rm -f beemp.dis beemp.bin beemp_elf *.o


好的,我们放在/home/jun/arm/ext0/下,然后make。。。。


第一个程序,让你的板子唱国歌(败笔)_第4张图片



》》beemp.c:5: error:expected '}' before numeric constant

额,是语法错误,数组中的数误加了一个空格,悲剧,重新编译:


第一个程序,让你的板子唱国歌(败笔)_第5张图片


》》/home/jun/arm/ext0/beemp.c:23:undefined reference to `__aeabi_uidiv'

额,经过一番查询,发现arm和 arm-linux –gcc 不支持浮点除法,很纠结啊,要自己实现除法,真蛋疼啊。然后用位移实现除法后代码为:


#define GPBCON (*(volatile unsigned long*)0x56000010)
#define GPBDAT (*(volatile unsigned long*)0x56000014)
/* 标准音调频率 */
unsigned int hzs[]={131,147,165,175,196,220,247,262,294,330,349,392,440,494,523,587,659,698,784,880,988,1047,1175,1319,1397,1568,1760,1976};
/*频率控制数组*/
char dots[]={8,28,10,12,12,13,28,28,12,28,10,28,8,12,12,12,10,28,28,8,28,5,5,5,5,5,5,8,'#'};		
/*延时*/
void delay(unsigned int u) 
{ 
	while(u--);
}
unsigned int div(unsigned int a,unsigned int b)     /*除法的简单唯一实现,不是精确值*/
{
	b = b >> 1;
	a = a >> b;
	return a;
}

void play_hz(unsigned int u)
{ 
	unsigned int i=u;
	while(i--){
		
 		GPBDAT &= ~(1);
		GPBDAT &= ~(0);
		
 		delay(div(18432,u-24));
	}
}

void play_sound(int i)
{
 	if(i<28) 
		play_hz(hzs[i-1]);
	else 
		delay(500);
}

int main(){
	GPBCON = (1<<1);
			
	while(1){
 		int i=0; 
		while(dots[i]!='#')
			play_sound(dots[i++]);
		delay(20000);
 }	
	return 0;
}


好的,排除了这些错误后,再make一下,又杯具了:


第一个程序,让你的板子唱国歌(败笔)_第6张图片


报错:

beemp.o:(.ARM.exidx+0x0): undefined reference to`__aeabi_unwind_cpp_pr0'

beemp.o:(.ARM.exidx+0x10): undefined reference to`__aeabi_unwind_cpp_pr1'

make: *** [beemp.bin] Error 1

这个错误是编译器造成的,原来之前配置的EABI-4.3.3 编译内核跟给力(编译busybox也很给力的),编译裸机程序就杯具了,真坑爹。只有换编译器了,换编译器容易,安装好办,不过你要把之前安装的EABI-4.3.3时配置的环境注释掉,换成新的编译器的bin目录,两个共存的话肯定会有问题了,就像老师提问张三回答问题,班里却有两个张三,不知道是哪一个。这里附上3.4.5的编译器(【下载地址】/*115网盘下载,如果链接过期请及时留言提醒,我第一时间更新下载链接*/),直接解压到对应位置,修改环境变了即可,具体方法见前边交叉编译环境配置的文章。

OK,一番周折后,配好新的交叉编译工具,我们重新make一下:


第一个程序,让你的板子唱国歌(败笔)_第7张图片


好的,顺利通过,得到了二进制的.bin文件,这个就是我们要的……验证奇迹的时刻到了,我们通过FTP工具把编译好的文件下载到windows下进行烧写;(你可以用sjf2440.exe直接裸板烧写,或者直接用uboot通过DNW下载到nandflash中运行);这里我通过DNW下载,因为之前没有介绍过这个下载过程,这里顺带的介绍一下:

1、开发板除了接电源线以为,还要接串口线和USB(接板子的host端,标准USB接口端连电脑)

2、用USB传输,还要安装相应的USB驱动,这个在开发板的光盘中可以找到,驱动是直接的驱动文件,在电脑的硬件管理里手动安装就好

3、安装好后,并连接好了开发板,打开SecureCRT,文件----》快速链接----》协议里选“Serial”,波特率115200,其他默认就好,然后,上电,在焦点在SecureCRT上的情况下点下空格键(或者其他按键),串口输出会停在uboot的菜单项,然后就可以进行下载操作了。/*不过前提是你的板子上已经烧有uboot,这里用的是TQ2440原厂带的uboot,最好把uboot烧到norflash中,norflash比较稳定,较nandflash位反转情况会稳定些,所以一般把bootloader放在norflash,把系统、测试程序、root文件系统放在nandflash,具体烧写uboot过程,用并口通过jtag接口烧写,也可以用jlink,具体做法在各个板子厂商的板子说明文档里应该都有介绍,并且肯定都比我说的专业、详细。我就不再嗷述了*/

第一个程序,让你的板子唱国歌(败笔)_第8张图片


4、 我的串口输出截图:


第一个程序,让你的板子唱国歌(败笔)_第9张图片


选择a,Download User Program(eg: uCOS-II or TQ2440_Test)。然后等待传输:


第一个程序,让你的板子唱国歌(败笔)_第10张图片


然后打开DNW.exe,按图选择你刚通过FTP考到的beep.bin,进行传输:


第一个程序,让你的板子唱国歌(败笔)_第11张图片


选择后提示下载到nand成功。


第一个程序,让你的板子唱国歌(败笔)_第12张图片


然后重启开发板,从nandflash启动。。。。。。。。

我的启动,我勒个去……一直“嘀~~~~”不对,应该是这样“嘀——”就不间断,更别提频率和声调了。看来只这样傻帽似的用寄存器控制它是不好办的,这个不懂电路和硬件太可怕了,看来这TOUT0的控制还是得用PWM。

额,我太单纯了,单纯的人总会受伤。此实验以失败告终。。。期待下次尝试,就凭着我们的爱国精神,这国歌是必须要唱的。不过好歹还是有些收获的。希望本文没让你失望了(我还是很自信的,哈哈)。



【本文doc文档及源码下载地址】


你可能感兴趣的:(linux,download,reference,makefile,编译器,delay)