感谢Funpack新一期的体验机会,本期活动中我选择的题目是:
任务1 - 开放题
- 自行搭配已有传感器,配合AVR64DD32 Curiosity Nano核心板的至少两个片内外设,完成任务,任务难度不低于以上任务。例如:搭配温度传感器和蜂鸣器,实现温度监控,当超过一定温度时报警。
一、项目设计思路
任务中的核心主控微控制器是Microchip公司的最新的AVR64DD32,具有功能强大的多种片上外设,比如I2C, SPI, CCL, 多种Timer模块等。本次项目计划完成的任务是超声波测距,所选择的模块是:
- 主控:AVR64DD32,本项目中使用到了TCB0和AC0以及UART0三个片上外设模块
- 超声波传感器:Adafruit提供的HC-SR04超声波测距模块。
项目实现的主要难点在于:
- 驱动超声波传感器HC-SR04正常工作
- 如何用AVR64DD32捕获并计算声波传播的时间,乘以声速即可计算出距离障碍物的距离。
本次项目中,我使用的是AVR64DD32的片上模拟外设AC0与TCB0来检测HC-SR04的Echo引脚脉冲高电平的宽度,使用了HC-SR04来收发超声波信号。下面先来熟悉一下超声波测距的基本原理以及如何使用这款来自Adafruit的HC-SR04来完成测距工作。
二、超声波测距的基本原理
超声波测距原理是在超声波发射装置(HC-SR04)发出超声波,它的根据是接收器接到超声波时的时间差,与雷达测距原理相似。 超声波发射器向某一方向发射超声波,在发射时刻的同时开始计时,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时。
(超声波在空气中的传播速度为340m/s,根据计时器记录的时间t(秒),就可以计算出发射点距障碍物的距离(s),即:s=340t/2)
通常来讲,超声波经发射物反射回来,由传感器接收端接收,再经过接收电路放大、整形。以嵌入式微核心的超声波测距系统,通过嵌入式设备记录超声波发射的时间和反射波的时间。当收到超声波的反射波时,接收电路输出端产生一个跳变。通过定时器计数,计算时间差,就可以计算出相应的距离。
本次选购的超声波传感器HC-SR04来自Adafruit,包括超声波发射器、接收器与控制电路。实物如下图所示,其中
- Vcc: +5V电源供电;
- Trig:输入触发信号(可触发测距);
- Echo: 传出信号回响(可以传回时间差);
- GND:接地。
基本参数如下:
- Power & Logic Voltage: DC 5V
- Current during measurment: 15mA
- Ultrasonic Frequency: 40 KHz
- Measuring Angle: 15º
- Trigger Input Signal: 10uS high pulse
- Sensor dimensions (excluding header): 45.5 x 20 x 15.5mm
- Weight: 8.7
根据产品手册描述,为了产生超声波,需要将 Trig 设置为高状态 10 µs。这将发出一个 8 周期的声波脉冲,它将以声音的速度传播,并将在 Echo 引脚中接收。Echo 引脚将输出声波传播的时间(以微秒为单位。之后通过测量Echo引脚高脉冲的时间,就可以获得声音来回传播的时间,进而计算出传播距离。
因此,如何用AVR64DD32来捕获并测量出Echo引脚上的高电平脉冲就成了本次设计的一个关键点。
三、基于AC0与TCB0的脉冲宽度测量
AVR64DD32的TCB0有一个非常有特色的功能就是芯片手册24.3.3.1.5节所描述的:输入捕获脉冲宽度测量模式。参考提供的示例图,这刚好是测量脉冲宽度的一个现成模块!根据自己对理解,这个TCB0的工作方式如下:
- 在检测到一个上升沿的时候,计数器CNT设置为BOTTOM,即0x0000;
- 检测到下一个下降沿的时候,继续捕获
- 检测到下一个上升沿的时候,产生中断,计数器CNT复位。
下图所示为官方数据手册中提供的该模式的工作原理:
所以,现在的重点是如果得到上图中的“Event Input”?这就要依赖AVR64DD32提供的事件系统“Event System”,这个无需CPU干预的外设能够使得一个外设作为“事件”的生产者,另一个外设直接作为“事件”的使用者。
这下图所示的“事件系统”模型中,我们已经确定TCB0可以用作“事件”的“Event user”,那“Event Generator”该用哪个外设来产生呢?
这本设计中,可以利用AVR64DD32的AC(模拟比较器)这个片上外设。它能够比较“Compare”两路输入信号的电平并产生一个数字信号,并且这个模拟比较器还能够生成“Event”。这刚好可以提供给TCB0使用!比如设定一个Negative输入为0.8V,当positive输入(连接到HC-SR04的Echo引脚)输入大于0.8V时,输出为高电平;当positive输入电平低于0.8v的时候,输出为低电平。
基于此,我们可以配置模拟比较器模块输出一个“Event”。
通过配置Event System,可以把模拟比较器的输出路由到TCB0作为输入。
介绍到这里,我们了解了模拟比较器模块AC0会输出“EVENT”,并且路由到TCB0后,TCB0由于工作在“Input Capture Pulse-Width Measurement Mode”,TCB0便可以方便的计算出脉冲宽度!此时,通过读取CCMP寄存器的值可以获取到高电平脉冲的持续了多少计数值,然后乘以TCB0模块等外设时钟频率即可计算出Echo信号的持续时间。
四、硬件系统设计
下图是简单的硬件连接,其中HC-SR04的Trigger引脚连接到AVR64DD32的PD1引脚,该引脚被被配置为输出模式;HC-SR04的Echo引脚连接到AVR64DD32的PD2引脚,该引脚被被配置为模拟比较器AC0的Positive Input模式。
右图为在图形化配置工具MCC中的Pin模块截图。
下面是主要的片上外设图形化配置界面展示。
在MCC中配置模拟比较器AC0:
在MCC 中配置“时间系统”中AC0所产生事件的使用者为TCB0:
在MCC中配置定时器/计数器B模块:TCB0
配置UART功能:
五、软件流程图
程序的大致处理流程如下:
其中的核心代码是在主函数中通过读取CCMP的值,根据TCB0外设模块等时钟频率,计算出声音传播的距离。
下面代码中的signal_pulse是高电平脉冲所对应的计数器值,这其实是声波来回传播的时间,需要除以2得到声波单程传播时间。TCB0的外设时钟频率为2MHz,因此声音传播的时间为(signal_pluse/2)*(1/(2,000,000))秒。然后再乘以34300,换算成cm。
while(1)
{
IO_PD1_TriggerSig_SetLow();
_delay_ms(2);
IO_PD1_TriggerSig_SetHigh();
_delay_ms(10);
IO_PD1_TriggerSig_SetLow();
if (TCB0.INTFLAGS & TCB_CAPT_bm)
{
/**
* First read the CNT register
* The interrupt flag is cleared by writing 1 to it, or when the Capture register
* is read in Capture mode
*/
//signal_period = TCB0.CNT;
signal_pulse = TCB0.CCMP;
asm("NOP");
printf("Calculate Dist...");
printf(" %f cm\r\n", signal_pulse/2.0/2*34300.0/1000000);
}
}
六、实物和UART上位机展示:
总结
非常开心能够完成本次Funpack活动的任务,通过本次项目,深入学习了UART模块,AC模拟比较器模块,TCB定时器模块等诸多外设的使用。增加了自己对AVR单片机的了解,并对MCC的图形化配置工具以及代码自动生成等高级功能有了更进一步的了解。
项目可以改进的地方非常多,比如增加屏幕显示模块,增加距离阈值蜂鸣器报警模块等。
最后衷心希望Funpack活动越办越好!