本帖最后由 okwh 于 2017-11-11 23:41 编辑
自平衡小车-2 超声测距
本篇验证超声测距模块HC_SR04 一、该模块参数: - 工作电压: 5V
- 工作电流: 15mA
- 工作频率: 40Hz
- 测距范围: 2cm~4m
- 测量角度: 15度
- 触发信号: 10us TTL
- 回声信号: TTL高电平持续时间
二、 设计(lpc54114板接口线定义见上篇表格) 模块有引线4根,电源5V和地从Arduino电源接口提供 触发信号和回声信号接PIO0_21 和PIO0_20,对应CTimer3_MAT0和Ctimer3_CAP0功能。 LPC54114的计时器功能很强大,每个计时器可同时实现4个匹配输出和4个输入捕获或多个PWM输出。简单的看,LPC54114的每个计时器至少可实现4个最简单计时器的功能。于是,我们可以很简单的用1个计时器绰绰有余地满足上面的时序图,完全控制超声测距模块(实际只使用了2个匹配、1个捕获捕2次)。 这里使用Timer3的0号匹配MAT0-对应管脚PIO0_21用于生成触发信号;使用Timer3的0号捕获CAP 0-对应管脚PIO0_20,以中断方式用于捕获回声信号上升沿和下降沿对应的记数,进一步用获得两个记数的差计算超声探测距离;同时使用无输出的1号匹配MAT1控制测量周期。
三、编程 基于例子SDK_2.2.1_LPCXpresso54114\boards\lpcxpresso54114\driver_examples\ctimer\simple_match修改。
配置管脚:PIO0_21和PIO0_20,增加到 pin_mux.c - #define PIN21_IDX 21u /*!< CTimer3_MAT0 Pin number for pin 21 in a port 0 */
- #define PIN20_IDX 20u /*!< CTimer3_CAP0 Pin number for pin 20 in a port 0 */
- ...........................
- const uint32_t port0_pin21_config = ( //P0_21 用于 CTIMER3_MAT0输出 触发 超声探测
- IOCON_PIO_FUNC3 | /* Pin is configured as CTIMER3_MAT0 */
- // IOCON_PIO_MODE_INACT | /* No addition pin function */
- IOCON_MODE_PULLDOWN | //默认下拉
- IOCON_PIO_INV_DI | /* Input function is not inverted */
- IOCON_PIO_DIGITAL_EN | /* Enables digital function */
- IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
- IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
- );
- IOCON_PinMuxSet(IOCON, PORT0_IDX, PIN21_IDX, port0_pin21_config); /* PORT0 PIN21 (coords: 11) is configured as CTIMER3_MAT0 */
- const uint32_t port0_pin20_config = ( //P0_20 用于 CTIMER3_Cap0输入 超声echo
- IOCON_PIO_FUNC3 | /* Pin is configured as CTIMER3_cap0 */
- // IOCON_PIO_MODE_INACT | /* No addition pin function */
- IOCON_MODE_PULLDOWN | //默认下拉 要CAP高电平
- IOCON_PIO_INV_DI | /* Input function is not inverted */
- IOCON_PIO_DIGITAL_EN | /* Enables digital function */
- IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
- IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
- );
- IOCON_PinMuxSet(IOCON, PORT0_IDX, PIN20_IDX, port0_pin20_config); /* PORT0 PIN20 (coords: 11) is configured as CTIMER3_Cap0 */
复制代码捕获回声中断:增加到 simple_match.c - static uint32_t count0 = 0; // one for Capture_RiseEdge
- static uint32_t count1 = 0; // one for Capture_FallEdge
- void ctimer_cap_callback(uint32_t flags)
- {
- if (count0==0)
- count0 = CTIMER3->CR[0] ;// CTIMER_CR_CAP(0) ; // CTIMER3 Capture_0 record
- else
- count1 = CTIMER3->CR[0] ;//CTIMER_CR_CAP(0) ; // CTIMER3 Capture_0 record
- }
- ctimer_callback_t ctimer_callback_table[] =
- {
- ctimer_cap_callback,
- NULL,
- NULL,
- NULL,//ctimer_match1_callback,
- NULL,
- NULL,
- NULL,
- NULL
- };
复制代码
主函数: 修改增加到 simple_match.c - #define CTIMER CTIMER3 /* Timer 0 */
- #define CTIMER_MAT_OUT kCTIMER_Match_0 /* Match output 0 p0_21*/
- #define CTIMER_CAP_INP kCTIMER_Capture_0 /* Capture 0 p0_20*/
- #define BUS_CLK_FREQ CLOCK_GetFreq(kCLOCK_AsyncApbClk)
- int main(void)
- {
- ctimer_config_t config;
- ctimer_match_config_t matchConfig;
- /* Init hardware*/
- /* attach 12 MHz clock to FLEXCOMM0 (debug console) */
- CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);
- /* Enable the asynchronous bridge */
- SYSCON->ASYNCAPBCTRL = 1;
- /* Use 12 MHz clock for some of the Ctimers */
- // CLOCK_AttachClk(kFRO12M_to_ASYNC_APB); //kCLOCK_AsyncMainClk kCLOCK_AsyncFro12Mhz
- CLOCK_AttachClk(kMAIN_CLK_to_ASYNC_APB);//kCLOCK_AsyncMainClk); //96MHz
-
- BOARD_InitPins();
- BOARD_BootClockFROHF48M();
- // BOARD_BootClockFROHF96M();
- BOARD_InitDebugConsole();
- PRINTF("CTimer match example to toggle the output on a match\r\n");
- CTIMER_GetDefaultConfig(&config);
- CTIMER_Init(CTIMER, &config);
- count0 =0; count1 =0;
-
- matchConfig.enableCounterReset = true; //mat1 后复位 重记数 控制测量周期
- matchConfig.enableCounterStop = false; //mat后不停止
- matchConfig.matchValue = BUS_CLK_FREQ /1;//0 ; // BUS_CLK_FREQ/1 即1秒 这里每秒测一次 说明书要求 > 60ms
- matchConfig.outControl = kCTIMER_Output_NoAction; //无输出关联
- matchConfig.outPinInitState = false; // 无效
- matchConfig.enableInterrupt = false; //匹配不中断
- CTIMER_SetupMatch(CTIMER, kCTIMER_Match_1, &matchConfig); //Timer3 mat1 no out
- CTIMER_SetupCapture(CTIMER,CTIMER_CAP_INP,kCTIMER_Capture_BothEdge,true); //捕获回声中断 ////Timer3 cap0 input p0_20, up echo start, down echo finish
- CTIMER_RegisterCallBack(CTIMER, &ctimer_callback_table[0], kCTIMER_SingleCallback);//kCTIMER_MultipleCallback); //echo fall intr
-
- matchConfig.enableCounterReset = false;// true; //mat0不复位 继续记数
- matchConfig.enableCounterStop = false; //mat后不停止
- matchConfig.matchValue = BUS_CLK_FREQ *11 / 1000000; // 11us 触发
- matchConfig.outControl = kCTIMER_Output_Toggle; //toggle输出
- matchConfig.outPinInitState = true;//false;// 计时器开启前的高低。 初始化为下拉低
- matchConfig.enableInterrupt = false; //匹配不中断
- CTIMER_SetupMatch(CTIMER, CTIMER_MAT_OUT, &matchConfig); //Timer3 mat0 out p0_21 trig
-
- CTIMER_StartTimer(CTIMER); //开始
- while (1)
- {
- if (count1!=0)
- {
- PRINTF("CTimer cap %d %d %d mm\r\n",count0,count1,(int32_t)(abs(count1-count0)/48*0.17)); // 0.17 mm /us, 48MHz
- count0 =0; count1 =0;
- }
- }
复制代码
四、结果 1) 放于桌面,对天花板测量: 距离1.847米,误差1cm左右;下图
2) 用手在声纳前逐渐移动,可看到距离4~16cm; 误差5mm左右;下下图
3) 10us触发信号,测距模块实际使用的可能是其上升沿触发,此信号长时间高电平没影响测距。
小心问题:
1) 小于27mm, 约声音传播总时间约小于15 us时,误差变大,且距离反会大幅度变大,测量失效。(说明书: 20mm下限)
2) 不同材质阻挡物声音反射效果不同,硬且平整材料 测距较准, 柔软弹性物质、有洞的材料如泡沫塑料、叉开的手指等 测距误差较大。3) 如果阻挡物在动态运动,也可能出现较大测距误差。
测量echo高电平持续时间: 我以为可以在一个cap管脚上cap一个信号的升和降、队列记录两个记数,实际是cap记数记录,一个cap只有一个记录寄存器,所以使用中断先把升记下,再次中断就是降的计时记数。这样是 一个管脚、二次中断。
还有一个办法,就是使用两个cap管脚接同一个echo信号,分别cap升和降,这样则需要两个管脚、降中断一个。 此未测试。
天花板测距
手移动:
系列:
|