从一开始,我就知道我需要在我的项目中加入一个复古玩具。
收到我自己的留声机后,我拿起随附的公对公 3.5 毫米音频线(以及三节不随附的 AA 电池),用一只手将电线握在一起,另一只手将手写笔固定在键盘上,从而确定输出信号的范围.
由于留声机输出的是单声道信号,因此我使用笔尖 (T) 作为输入,使用套管 (S) 作为接地(顺便说一下,R 代表环)。
基本的留声机有一个用于 3 种声音模式的开关、一个颤音开关、一个电源开关、一个音量旋钮和一个调谐旋钮。我建议在最大音量和无颤音下使用配置文件 1,下面的所有结果都使用这些设置。调准时,留声机的最低音符是 A (110Hz),最高音符是 E (329.63 Hz)。当留声机开启时(可以说是“预热”),留声机的输出最小电压范围为 -1.7 V 至 -100 mV,峰值电压范围为 1.7 V 至 3.5 V。自 TI MSP430G2553无法读取负电压,如果您移动参考电压,Uno 只能读取负电压,我决定使用 TI LM741 运算放大器构建增益和转换威廉希尔官方网站 。
可以构建一个简单的威廉希尔官方网站 ,将 [-2, 2] V 转换为 [0, 4[ V 并应用增益以获得输出 [0, 3] V。
可以使用来自 MSP430G2553 的 3.3V 电源和一个 10k 电位器来控制同相输入。图中的 R1 和 Rf 选择为 9.1 kOhm 和 12 kOhm,以实现 9.1k/12k ≅ 3/4 增益。还选择了较大的电阻器来限制电流量。考虑到这一点,我在 LTSpice(您可以在此处免费下载)中设计和仿真威廉希尔官方网站 。
幸运的是,TI 为他们的许多部件提供了 SPICE 模型,这样的精确仿真是可能的。(您可以在此处下载 LM741.mod )。模拟给出了从 [-2, 2] V 到 [0, 3.3] V 的预期偏移,所以是时候构建威廉希尔官方网站 了!
威廉希尔官方网站 中使用的唯一部件是一个 9.1k 和 12k 欧姆电阻器、一个 0.1μ 法拉电容器、一个 10k 电位器、TI LM741、一个 3.5mm 音频插孔和一些电线。
焊接威廉希尔官方网站 后,使用 +12/-12 V 直流电源和 MSP430G2553 的 3.3 V 电压为其供电。从函数发生器提供 4 V 峰峰值的输入正弦波产生了我想要看到的结果。
现在提供来自留声机的输入并调整电位器偏移...
您会注意到,根据定义,高音 (E 329.63 Hz) 比低音 (A 110 Hz) 紧凑得多。这会产生采样问题,稍后将对此进行解释。
MSP4302553的作用是对音频信号进行采样,发送给arduino,根据接收到的信息,驱动舵机。ADC10 和定时器 A0 设置为以 8kHz 采样。
// Init ADC10
// Control Register 0
ADC10CTL0 = SREF_0; // Vr+ = Vcc and Vr- = Vss (default)
ADC10CTL0 += ADC10SHT_1; // 8 X ADC10CLKs
// ADC10SR: 2000 ksps (default)
// REFOUT: reference output off (default)
// REFBURST: continuous (default)
// MSC: single conversion mode (default)
// REFON: reference generator off (default)
ADC10CTL0 += ADC10ON; // ADC10 On
ADC10CTL0 += ADC10IE; // interrupt enabled
// Control Register 1
ADC10CTL1 = INCH_3; //input channel A3 (default)
ADC10CTL1 += SHS_0; // sample and hold source ADC10SC (default)
// ADC10DF: straight binary data format (default)
ADC10CTL1 += ADC10DIV_0; // Clock divider, try values and check noise
ADC10CTL1 += ADC10SSEL_0; // clock source ADC10SC
ADC10CTL1 += CONSEQ_0; // Single channel single conversion
// analog enable control register 0
ADC10AE0 = 8; // Enable A3 as ADC channel
引脚 1.4(任意)成为从机选择并初始化 SPI
// Initialize Port 1, P1.0 LED, P1.4 SS
P1SEL &= ~(BIT0 + BIT4); // P1.0 and P1.4 GPIO
P1SEL &= ~(BIT0 + BIT4); // P1.0 and P1.4 GPIO
P1REN &= ~(BIT0 + BIT4); // P1.0 and P1.4 Resistor disabled
P1DIR |= BIT0 + BIT4; // Set P1.0 and P1.4 to output direction
P1OUT &= BIT4; // Initially set P1.4/SS high
// Port 1 SPI pins, P1.5 SCLK, P1.6 MISO, P1.7 MOSI
P1SEL |= BIT5 + BIT7 + BIT6; // Secondary Peripheral Module Function for P1.5-1.7
P1SEL2 |= BIT5 + BIT7 + BIT6; // Secondary Peripheral Module Function for P1.5-1.7
// Polarity and SCLK for SPI
UCB0CTL0 = UCCKPH + UCCKPL; // first edge: data capture, following edge: data update , SCLK inactive state High
// Initialize SPI
UCB0CTL0 |= UCMSB + UCMST + UCSYNC + UCMODE_0; // MSB first, master, 3-pin, 8-bit synchronous
UCB0CTL1 = UCSSEL_2 + UCSWRST; // SMCLK, enable SW Reset
// bit rate: SMCLK/x=SCLK
// smclk same as arduino uno (16 Mhz)
UCB0BR0 = 32; // low byte, divide by
// 4 divider or greater, 8 and 16 causes issues, 32 seems okay
UCB0BR1 = 0; // same as 1 divider, high byte
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
IFG2 &= ~UCB0RXIE; // Clear RX interrupt flag in case it was set during init
IE2 |= UCB0RXIE; // Enable USCI0 RX interrupt
端口 2 设置为使用 TA1 和 TA2 引脚创建 PWM 信号来控制伺服系统。
// Init Port 2
// setup P2.1 with Timer1_A3.TA1 and P2.4 with Timer1_A3.TA2
P2DIR |= 0x12;
P2SEL |= 0x12;
P2SEL2 = 0;
退一步,让我们谈谈 SPI。
它有很多内容,但归根结底是摩托罗拉在 1980 年代创建的通信接口规范,可用作双向通道。主机 (MSP430G2553) 和从机 (Uno) 需要共享四条主要线路:SCLK、MISO、MOSI 和 SS。SCLK(串行时钟)由主机生成,以便通信保持同步。MISO(Master In Slave Out)和 MOSI(Master Out Slave In 是街道的两侧,指示交通行驶的方向(有时称为 SOMI 和 SIMO)。SS(Slave Select)告诉从站何时应该收听master, 以及何时忽略它。这允许一个 master 拥有多个 slaves 而不会导致通信错误。配置 SPI 有不同的方法,但我选择的设置(如上面代码中指定的)看起来像这样。
该图可在 MSP430x2xx 系列用户指南的第 448 页找到。
Arduino 证明了一个使 SPI 通信变得容易的库,但只是为了让 Arduino 成为主人(去图)。
pinMode(MISO, OUTPUT);
// turn on SPI with interrupts, slave mode, msbit first
// clock idle when high, sample on falling edge of clock
SPCR = _BV(SPE) + _BV(SPIE) + _BV(CPOL) +_BV(CPHA);
/*
* SPIE - Enables the SPI interrupt when 1
* SPE - Enables the SPI when 1
* DORD - Sends data least Significant Bit First when 1, most Significant Bit first when 0
* MSTR - Sets the Arduino in master mode when 1, slave mode when 0
* CPOL - Sets the data clock to be idle when high if set to 1, idle when low if set to 0
* CPHA - Samples data on the falling edge of the data clock when 1, rising edge when 0
* SPR1 and SPR0 - Sets the SPI speed, 00 is fastest (4MHz) 11 is slowest (250KHz)
*
*/
设置只需要两行代码,但通信中的大部分困难在于让 Uno 作为奴隶合作。Uno 和 MSP430G2553 均以 16Mhz 运行,但 MSP430G2553 可以通过使用较小的分频器 (UCB0BRx) 设置波特率控制寄存器来更快地通过 SPI 进行通信。Uno 至少需要一个 4 分频器 (4 Mhz),但我发现偶尔会出现错误传输(0x1234 变为 0x3400),直到 32 分频器 (500 kHz)。我选择将 MSP430G2553 作为主器件的原因之一是 ADC 采用 10 位样本,而 Uno 只能采用 8 位样本。这里越多越好,因为它提供了更高的分辨率,这意味着 MSP430G2553 可能能够看到 1 mV 的差异,而 Uno 可能看不到。虽然这两个设备之间的 SPI 一次发送 8 位,可以简单地发送 2 组 8 位来获取 MSP430G2553 的 10 位值。唯一的问题是确保较慢的 Arduino 不会落后。
最初的目的是在 Uno 上使用 FFT 或音调检测库,但这只会让事情变得更慢。最终,由于我知道来自留声机的信号的形状(每个周期一个上升沿和一个下降沿),所以我采用了一种更简单、更快速的方法。当前一个平均值小于阈值时,我只是等待最后 4 个样本的平均值大于阈值。这告诉我我触发了上升沿。然后我数了多久,直到再次发生这种情况并存储起来。然后我会简单地取最后 10 个计数/周期的中值来过滤掉任何异常值。这会瞬间发生,并允许伺服系统实时做出反应。
只需更改 MSP430G2553 上 PWM 信号的占空比即可移动伺服器。例如:
TA1CCR2 = 2100; TA1CCR1 = 2100;
我可能会尝试改进代码,以便稍后伺服在高频下更加稳定。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !