简 介: 利用ESP32的MicroPython PWM 模块可以产生很精确的输出频率,但是所有MicroPython的PWM都共享同一个Timer,所以他们的基频都相同。利用MM32 MicroPython可以使用其中两个硬件Timer, 但是输出的频率精度无法满足要求。因此: 要么使用其它的信号源来检测DTMF; 要么通过mem32来提高MM32的输出频率的精度;
关键词
: MM32,MicroPython,PWM,DTMF
DTMF是由Bell实验室在上个世纪发明的用于电话拨号的方案,该方案可以在相同的电话心中通过双音频来传递电话号码编码。在DTMF的原理:为什么选择这些频率?测试了这些频率选择是为了能够最大化频率值及其谐波之间差异最大化。
本文测试一下对于带有谐波的双音频信号,也就是通过ESP8266产生的双音频产生的方波信号是否可以用于双音频信号。
利用ESP8266的两个通道的 PWM 产生双音频,然后通过不同的方式进行叠加在一起,测试该信号是否可以利用DTMF硬件解码器进行正确的解码。
在ESP32-S模块转接板设计与实现给出了ESP32硬件设计与接口。
▲ 图1.1.1 ESP32的接口说明
参考 MicroPython官网 给出了ESP32的编程参考资料。
利用ESP32转接模块的PIN17,18(从右边数第4,3管脚)输出PWM波形。
from machine import Pin,PWM import time led1 = Pin(5, Pin.OUT) led2 = Pin(18, Pin.OUT) lowf = [697, 770, 852, 941] highf = [1209, 1336, 1477, 1633] pwm1 = PWM(Pin(15), freq=lowf[0], duty=0x1ff) pwm2 = PWM(Pin(2), freq=highf[0], duty=0x1ff) while True: led1.on() led2.off() time.sleep_ms(100) led2.on() led1.off() time.sleep_ms(100)
▲ 图1.1.2 输出的PWM波形
输出结果可以看到 Pin15,Pin2对应的PWM向相同的PWM Timer,可以看到它输出的PWM 的频率是随着最后一个PWM频率对应的数值。
在 MicroPython Machine.PWM 中给出了对于共享相同的Timer的PWM都具有相同的基频。那么问题来了:如何定义PWM使用不同的Timer?
在 Quick reference for ESP32 PWM 给出了在ESP32中最多能够有8个不同的PWM频率,这也说明可以在ESP32中设置不同的PWM的基频。
在 Using micropython on ESP32, how to have 2 PWM pins with different frequencies? 也有人提出了相同的问题。并给出了链接 **ports/esp32/machine_pwm: Add support for all PWM timers and modes. ** 中给出了ESP32 MicroPython的新的实现版本。
pwm3 = PWM(Pin(2), freq=440, timer=0, speed_mode=PWM.LOW_SPEED_MODE) pwm4 = PWM(Pin(15), freq=880, timer=1, speed_mode=PWM.LOW_SPEED_MODE)
但是经过测试,上面的函数在当前的ESP32模块的软件中不支持。
既然ESP32不支持多个TIMER,那么使用 MM32中的MicroPython 来进行实验。
最新的版本来自于灵动苏勇的MicroPython版本:
D:\zhuoqing\window\ARM\IAR\MM32\MicroPython
▲ 图1.2.1 利用MM32-LinkProgram下载程序
▲ 图1.2.2 下载MM32 MicroP越活娘
在 MM32F3277 MicroPython 实验板设计和软件测试 给出了实验电路板的电路图。
▲ 图1.2.3 MM32F3277 MicroPython 实验板
下表给出了MM32中的两个PWM两个通道的PWM分别使用TIM3,TIM6的PWM,利用PWM0,PWM4,使用TIM3,TIM4测试。
【表1-1 MM32 PWM资源配置】PWM | 定时器 | GPIO |
---|---|---|
PWM0 | TIM3 | PA6 |
PWM1 | TIM3 | PA7 |
PWM2 | TIM3 | PB0 |
PWM3 | TIM3 | PB1 |
PWM4 | TIM4 | PB6 |
PWM5 | TIM4 | PB7 |
PWM6 | TIM4 | PB8 |
PWM7 | TIM4 | PB9 |
from machine import Pin,PWM import utime led0 = Pin('PB2', mode=Pin.OUT_PUSHPULL) pwm0 = PWM(0, freq=500, duty=500) pwm1 = PWM(4, freq=501, duty=500) print("Test PWM.") while True: led0(1-led0()) utime.sleep_ms(100)
▲ 图1.2.4 在A6,B6输出500,501Hz的PWM波形
来自于苏勇的这个PWM版本,输出频率存在着误差。比如设置freq=490,但输出频率为:492.3Hz。
▲ 图1.2.5 在500-600Hz之间设置频率与输出频率的差异
from machine import Pin,mem32,PWM import utime led = Pin('PB2', Pin.OUT_PUSHPULL) f = 697 pwm0 = PWM(0, freq=f, duty=500) pwm1 = PWM(4, freq=f, duty=500) from micropython import const APB2PERIPH_BASE = const(0x40010000) UART1_BASE = const(APB2PERIPH_BASE + 0x3800) UART1_RDR = const(UART1_BASE + 1*4) UART1_CSR = const(UART1_BASE + 2*4) replbuf = bytes(0) def procREPL(f): global replbuf if mem32[UART1_CSR] & 0x2: replbuf += bytes([mem32[UART1_RDR]]) if replbuf[-1:] == b'\r': f(replbuf[:-1]) replbuf = bytes(0) def f(s): global pwm0,pwm1 frq= int(s) print(frq) pwm0.deinit() pwm1.deinit() pwm0 = PWM(0, freq=frq, duty=500) pwm1 = PWM(4, freq=frq, duty=500) while True: procREPL(f)
▲ 图1.2.6 500 - 2000范围内的频率差异
下图给出了DTMF编码所使用的频率取值。
▲ 图1.2.3 DTMF频率编码
测量MM32 MicroPython PWM输出的方波频率。
[697, 770, 852, 941, 1209, 1336, 1477, 1633]
》[-3.799987999999985, -4.270020000000045, -5.229979999999955, -0.270020000000045, -6.3000489999999445, -16.300048999999944, -23.200072999999975, -22.300048999999944]
通过上面的测试,可以看到MM32 MicroPython PWM的频率不适合用于 产生双音频信号的测试。
利用ESP32的MicroPython PWM 模块可以产生很精确的输出频率,但是所有MicroPython的PWM都共享同一个Timer,所以他们的基频都相同。利用MM32 MicroPython可以使用其中两个硬件Timer, 但是输出的频率精度无法满足要求。
因此:
■ 相关文献链接:
● 相关图表链接:
from machine import Pin,mem32,PWM import utime led = Pin('PB2', Pin.OUT_PUSHPULL) f = 697 pwm0 = PWM(0, freq=f, duty=500) pwm1 = PWM(4, freq=f, duty=500) from micropython import const APB2PERIPH_BASE = const(0x40010000) UART1_BASE = const(APB2PERIPH_BASE + 0x3800) UART1_RDR = const(UART1_BASE + 1*4) UART1_CSR = const(UART1_BASE + 2*4) REPLBUF_LENGTH = const(64) replbuf = [0]*REPLBUF_LENGTH replpoint = 0 def procREPL(f): global replbuf,replpoint if mem32[UART1_CSR] & 0x2: bc = mem32[UART1_RDR] if replpoint < REPLBUF_LENGTH-1: replbuf[replpoint] = bc replpoint += 1 if bc == 13: f(bytes(replbuf[0:replpoint-1])) replpoint = 0 def f(s): global pwm0,pwm1 frq= int(s) print(frq) pwm0.deinit() pwm1.deinit() pwm0 = PWM(0, freq=frq, duty=500) pwm1 = PWM(4, freq=frq, duty=500) while True: procREPL(f)
#!/usr/local/bin/python # -*- coding: gbk -*- #============================================================ # TEST3.PY -- by Dr. ZhuoQing 2022-02-05 # # Note: #============================================================ from headm import * # = from tsmodule.tsstm32 import * setf = range(500, 2000, 5) outf = [] stm32cmd('SNDCD%d\r'%setf[0]) time.sleep(2) for f in setf: stm32cmd('SNDCD%d\r'%f) printf(f) time.sleep(1) meter = meterval() outf.append(meter[0]) tspsave('measure', setf=setf, outf=outf) delf = [f1-f2 for f1,f2 in zip(setf, outf)] plt.plot(setf, delf) plt.xlabel("SetFrequency") plt.ylabel("Delta Frequency") plt.grid(True) plt.tight_layout() plt.show() printf('\a') #------------------------------------------------------------ # END OF FILE : TEST3.PY #============================================================