雖然是敗筆,但是文中基本上介紹了一個小應用實現及問題分析的全過程,希望能夠對你有幫助,大膽貼出!畢竟這篇文章寫了好久。。。額,寫文章的人傷不起啊傷不起。。。
學生時代總會有這麼一句笑話:“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底板原理圖裏):
我們看到了只有一條接入的控制線 TOUT0 ,讓我們到S3C2440的針腳中找找它去》》》》》》(在TQ2440_V2核心板原理圖.pdf中,直接ctrl+F搜索一下)
我們看到TOUT0和GPB0是共用一個針腳的,就是可以通過GPIO接口來控制這個針腳輸出高低電平,從而控制Buzzer的聲響和聲調,咱們現在就去S3C2440的datasheet裏探尋一下這個針腳的控制信息》》》》》
圖中我標出了一些信息,這裏有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。。。。
》》beemp.c:5: error:expected '}' before numeric constant
額,是語法錯誤,數組中的數誤加了一個空格,悲劇,重新編譯:
》》/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一下,又杯具了:
報錯:
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一下:
好的,順利通過,得到了二進制的.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,具體做法在各個板子廠商的板子說明文檔裏應該都有介紹,並且肯定都比我說的專業、詳細。我就不再嗷述了*/
4、 我的串口輸出截圖:
選擇a,Download User Program(eg: uCOS-II or TQ2440_Test)。然後等待傳輸:
然後打開DNW.exe,按圖選擇你剛通過FTP考到的beep.bin,進行傳輸:
選擇後提示下載到nand成功。
然後重啓開發板,從nandflash啓動。。。。。。。。
我的啓動,我勒個去……一直“嘀~~~~”不對,應該是這樣“嘀——”就不間斷,更別提頻率和聲調了。看來只這樣傻帽似的用寄存器控制它是不好辦的,這個不懂電路和硬件太可怕了,看來這TOUT0的控制還是得用PWM。
額,我太單純了,單純的人總會受傷。此實驗以失敗告終。。。期待下次嘗試,就憑着我們的愛國精神,這國歌是必須要唱的。不過好歹還是有些收穫的。希望本文沒讓你失望了(我還是很自信的,哈哈)。
。
。