使用 for 循环的微控制器 p18f4520 的音频
Posted
技术标签:
【中文标题】使用 for 循环的微控制器 p18f4520 的音频【英文标题】:Audio tone for Microcontroller p18f4520 using a for loop 【发布时间】:2014-08-05 15:03:05 【问题描述】:我正在使用 C 编程为微控制器 P18F4520 编程音频。 我正在使用 for 循环和延迟来执行此操作。我还没有学到任何其他方法,而且我必须使用 for 循环和延迟来为目标板生成音频。扬声器的端口位于 RA4。这是我到目前为止所做的。
#include <p18f4520.h>
#include <delays.h>
void tone (float, int);
void main()
ADCON1 = 0x0F;
TRISA = 0b11101111;
/*tone(38.17, 262); //C (1)
tone(34.01, 294); //D (2)
tone(30.3, 330); //E (3)
tone(28.57, 350); //F (4)
tone(25.51, 392); //G (5)
tone(24.04, 416); //G^(6)
tone(20.41, 490); //B (7)
tone(11.36, 880); //A (8)*/
tone(11.36, 880); //A (8)
void tone(float n, int cycles)
unsigned int i;
for(i=0; i<cycles; i++)
PORTAbits.RA4 = 0;
Delay10TCYx(n);
PORTAbits.RA4 = 1;
Delay10TCYx(n);
所以你可以看到我所做的是我创建了一个音调函数,其中 n 代表延迟,周期代表 for 循环中的周期数。我不确定我的计算是否正确,但到目前为止,这是我所做的,并且确实产生了音调。我只是不确定它是否真的是 A 音或 G 音等。我如何计算是首先我会找出频率音例如 A 音的频率为 440Hz。然后我会找到它的周期,它将是 1/440Hz。然后对于占空比,我希望音调只发出一半的蜂鸣声,即 50%,所以我将周期除以 2,即 (1/440Hz)/2 = 0.001136s 或 1.136ms。然后我将为微控制器 4*(1/2MHz) 计算 1 个周期的延迟,即 2µs。所以这意味着对于 1 个周期,它将延迟 2µs,比率将为 2µs:1cyc。因此,为了获得 1.136ms 的周期数,它将是 1.136ms:1.136ms/2µs,即 568 个周期。目前在这部分我已经询问了 n 中应该是什么,其中 n 在 Delay10TCYx(n) 中。我得到的是,只需将 10 乘以 11.36,对于音调 A,它将是 Delay10TCYx(11.36)。至于周期,我想延迟 1 秒,所以 1/1.136ms 即 880。这就是为什么在我的音调 A 方法中它是音调(11.36、880)。它会产生一个音调,我已经找到了音调的范围,但我不确定它们是否真的是音调 C D E F G G^ B A。
所以我的问题是 1. 我如何真正计算音 A 的延迟和频率? 2. 对于“循环”的 for 循环的状态是循环数,但从我从问题 1 中得到的答案来看,我应该使用多少个循环来改变音调 A 的时间段?循环次数越多,音A的周期就越长?如果是这样,我怎么知道多长时间? 3.当我使用函数播放音调时,与我在main方法中直接使用for循环时相比,它会以某种方式产生不同的音调。为什么会这样? 4. 最后,如果我想停止代码,我该怎么做?我尝试过使用 for 循环,但它不起作用。
一个简单的解释会很好,因为我只是一个学生,正在从事一个使用 for 循环和延迟来产生音调的项目。我在其他地方搜索过人们使用不同的东西,如 WAV 或类似的东西,但我只是想知道如何使用 for 循环和音频延迟。
非常感谢您的帮助。
【问题讨论】:
【参考方案1】:首先,您需要了解如何以任意时间间隔生成中断的一般方法。这让您知道您可以在每 x
微秒内执行一次特定操作,[1-2]。
已有项目在 PIC 上播放特定音调(以赫兹为单位),就像您正在尝试做的那样,[3-4]。
接下来,您需要采用另一种方法来生成音调。对于您的 delay
函数,您实际上是在白白消耗 CPU,而实际上它可以做其他事情。你最好直接使用定时器中断,这样你就不会“通过空闲来烧CPU”。
实现此功能后,您只需知道您尝试生成的音符的相应频率,方法是使用公式从特定音符 [5] 生成频率,或使用查找表 [6]。
-
PIC timer0 产生 1 ms 或 1 sec 中断的过程是什么?,访问时间:2014-07-05,
<http://www.edaboard.com/thread52636.html>
PIC18 定时器简介——PIC 微控制器教程,访问时间:2014-07-05,<http://extremeelectronics.co.in/microchip-pic-tutorials/introduction-to-pic18s-timers-pic-microcontroller-tutorial/>
在 PIC16F87x 微控制器上生成铃声,访问时间:2014 年 7 月 5 日,<http://retired.beyondlogic.org/pic/ringtones.htm>
http://retired.beyondlogic.org/pic/ringtones.htm
AN655 - D/A 转换使用 PWM 和 R-2R 梯形图生成正弦波和 DTMF 波形,访问时间:2014 年 7 月 5 日,<http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1824&appnote=en011071>
频率表方程,访问时间:2014-07-05,<http://www.phy.mtu.edu/~suits/NoteFreqCalcs.html>
等律音阶的频率,A4 = 440 Hz,于 2014 年 7 月 5 日访问,<http://www.phy.mtu.edu/~suits/notefreqs.html>
【讨论】:
【参考方案2】:如何计算延迟周期数以获得 440Hz 的音调?我会假设你的时钟速度是 1/2MHz 或 500kHz,正如你在问题中所写的那样。
1) 500kHz 时钟速度对应于每 2us 一个 tic。由于一个周期是 4 个时钟 tic,一个周期持续 8 us。
2) 440Hz 的频率对应于 2.27ms 或 2270us 或 283 个周期的周期。
3) 每个周期调用两次延迟,因此 A 的延迟应该是大约 141 个周期。
关于你的音调函数......当你编译你的代码时,你必须面对某种警告,比如warning: (42) implicit conversion of float to integer
......延迟函数的原型是void Delay10TCYx(unsigned char);
:它需要一个无符号字符,而不是一个浮子。你不会得到任何浮点精度。你可以试试这样的:
void tone(unsigned char n, unsigned int cycles)
unsigned int i;
for(i=0; i<cycles; i++)
PORTAbits.RA4 = 0;
Delay1TCYx(n);
PORTAbits.RA4 = 1;
Delay1TCYx(n);
为了准确,我改成了Delay1TCYx()
。现在,1 秒的 A 调将是 tone(141,440)
。 1 秒的 880Hz 音调将是 tone(70,880)
。
总是有一个while(1)
是关于 PIC 的所有示例...如果您只需要在开始时发出一声哔哔声,请执行以下操作:
void main()
ADCON1 = 0x0F;
TRISA = 0b11101111;
tone(141,440);
tone(70,880);
tone(141,440);
while(1)
关于嵌入函数时的音调变化,请记住,每个操作至少需要一个周期。调用函数可能需要几个周期。也许声明static inline void tone (unsigned char, int)
会是件好事……
然而,正如@Dogbert 所暗示的那样,使用delays.h
对于初学者来说是一个好的开始,但不要习惯它!微控制器有很多功能可以避免计数并节省一些时间进行有用的计算。
【讨论】:
以上是关于使用 for 循环的微控制器 p18f4520 的音频的主要内容,如果未能解决你的问题,请参考以下文章