一. 前言
本文继续来实现超声波传感器距离采集。
传感器见3942 Adafruit Industries LLC | 超声波接收器、发射器 - DigiKey
5V供电,驱动Trig给 10uS以上高电平, echo检测高电平时间,即超声波来回时间,一半时间对应的即距离。这里如果是3.3V系统则需要对echo进行分压(附送了2个10K电阻)。
二. GPIO驱动
驱动trig发送高脉冲。这里使用引脚P3.12
Gpio.c
#include "fsl_common.h"
#include "fsl_port.h"
#include "fsl_gpio.h"
#include "pin_mux.h"
#define BOARD_TRIG_GPIO GPIO3 /*!<@brief GPIO peripheral base pointer */
#define BOARD_TRIG_GPIO_PIN 12U /*!<@brief GPIO pin number */
#define BOARD_TRIG_GPIO_PIN_MASK (1U << 12U) /*!<@brief GPIO pin mask */
/* Symbols to be used with PORT driver */
#define BOARD_TRIG_PORT PORT3 /*!<@brief PORT peripheral base pointer */
#define BOARD_TRIG_PIN 12U /*!<@brief PORT pin number */
#define BOARD_TRIG_PIN_MASK (1U << 12U) /*!<@brief PORT pin mask */
const gpio_pin_config_t trig_pin_config = {
.pinDirection = kGPIO_DigitalOutput,
.outputLogic = 0U
};
const port_pin_config_t trig_port_pin = {/* Internal pull-up/down resistor is disabled */
kPORT_PullDisable,
/* Low internal pull resistor value is selected. */
kPORT_LowPullResistor,
/* Fast slew rate is configured */
kPORT_FastSlewRate,
/* Passive input filter is disabled */
kPORT_PassiveFilterDisable,
/* Open drain output is disabled */
kPORT_OpenDrainDisable,
/* Low drive strength is configured */
kPORT_LowDriveStrength,
/* Normal drive strength is configured */
kPORT_NormalDriveStrength,
/* Pin is configured as P3_12 */
kPORT_MuxAlt0,
/* Digital input enabled */
kPORT_InputBufferEnable,
/* Digital input is not inverted */
kPORT_InputNormal,
/* Pin Control Register fields [15:0] are not locked */
kPORT_UnlockRegister};
void gpio_init(void)
{
CLOCK_EnableClock(kCLOCK_GateGPIO3);
CLOCK_EnableClock(kCLOCK_GatePORT3);
RESET_ReleasePeripheralReset(kGPIO3_RST_SHIFT_RSTn);
RESET_ReleasePeripheralReset(kPORT3_RST_SHIFT_RSTn);
/* Initialize GPIO functionality on pin PIO3_12 (pin 38) */
GPIO_PinInit(BOARD_TRIG_GPIO, BOARD_TRIG_PIN, &trig_pin_config);
/* PORT3_12 (pin 38) is configured as P3_12 */
PORT_SetPinConfig(BOARD_TRIG_PORT, BOARD_TRIG_PIN, &trig_port_pin);
}
void gpio_trig_set(uint8_t level)
{
if (level) {
GPIO_PortSet(BOARD_TRIG_GPIO, 1u << BOARD_TRIG_GPIO_PIN);
} else {
GPIO_PortClear(BOARD_TRIG_GPIO, 1u << BOARD_TRIG_GPIO_PIN);
}
}gpio.h
#ifndef GPIO_H #define GPIO_H void gpio_init(void); void gpio_trig_set(uint8_t level); #endif
注意:
GPIO和PORT都要使能时钟释放复位,否则会进入hardfault
CLOCK_EnableClock(kCLOCK_GateGPIO3);
CLOCK_EnableClock(kCLOCK_GatePORT3);
RESET_ReleasePeripheralReset(kGPIO3_RST_SHIFT_RSTn);
RESET_ReleasePeripheralReset(kPORT3_RST_SHIFT_RSTn);
三. Timer驱动
为了定时发送trig,使用一个定时器。
Timer.c
#include "fsl_ctimer.h"
#include "fsl_debug_console.h"
#define FREE_CTIMER CTIMER1 /* Timer 1 for free run*/
void timer_freetimer_init(void)
{
/* CTimer functional clock needs to be greater than or equal to SYSTEM_CLK */
CLOCK_SetClockDiv(kCLOCK_DivCTIMER1, 16); /* Max div 16 96/16=6M */
CLOCK_AttachClk(kFRO_HF_to_CTIMER1);
//frohf = CLOCK_GetCTimerClkFreq(kCLOCK_FroHf);
//uint32_t systemclk = CLOCK_GetCTimerClkFreq(kCLOCK_SYSTEM_CLK);
//CLOCK_SetClockDiv(kCLOCK_DivCTIMER1, frohf/systemclk);
uint32_t ctimerclk = CLOCK_GetCTimerClkFreq(1);
PRINTF("ctimer1clk=%d\r\n",ctimerclk);
ctimer_config_t config;
CTIMER_GetDefaultConfig(&config);
CTIMER_Init(FREE_CTIMER, &config);
CTIMER_StartTimer(FREE_CTIMER);
}
uint32_t timer_freetimer_get(void)
{
return CTIMER_GetTimerCountValue(FREE_CTIMER);
}
void timer_freetimer_delayus(uint32_t us)
{
uint32_t t0 = timer_freetimer_get();
uint32_t t1;
while(1){
t1 = timer_freetimer_get();
if(t1 - t0 >= us*6) {
break;
}
}
}timer.h
#ifndef TIMER_H #define TIMER_H void timer_freetimer_init(void); uint32_t timer_freetimer_get(void); void timer_freetimer_delayus(uint32_t us); #endif
注意:
CTimer的时钟频源必须要大于等于SYSTEM_CLK
否则仿真运行到CTIMER_Init时仿真挂掉
分频最大16分频。
四. 脉宽捕获
使用ctimer得捕获功能,要捕获高脉宽,所以使用两个引脚,P1.8和P1.9
一个捕获上升沿,一个捕获下降沿,两者之差几位高脉宽。
Capture.c
#include "fsl_common.h"
#include "fsl_port.h"
#include "fsl_gpio.h"
#include "fsl_inputmux.h"
#include "pin_mux.h"
#include "fsl_debug_console.h"
#include "fsl_ctimer.h"
#define CAPTURE_CTIMER CTIMER0 /* Timer 0 for capture */
static volatile uint32_t s_cap_value = 0;
static volatile int s_done_flag = 1; /* -1 timeout 1 done 0 not done*/
static volatile uint32_t s_cap0_value[2];
static volatile uint32_t s_cap0_tog = 0;
static volatile uint32_t s_cap1_value[2];
static volatile uint32_t s_cap1_tog = 0;
void ctimer_capture0_callback(uint32_t flags)
{
//CTIMER_ClearStatusFlags(CAPTURE_CTIMER, kCTIMER_Capture0Flag);
//s_cap0 = CTIMER_GetCaptureValue(CAPTURE_CTIMER, kCTIMER_Capture_0);
}
void ctimer_capture1_callback(uint32_t flags)
{
uint32_t cap0;
uint32_t cap1;
//CTIMER_ClearStatusFlags(CAPTURE_CTIMER, kCTIMER_Capture1Flag);
//s_cap1 = CTIMER_GetCaptureValue(CAPTURE_CTIMER, kCTIMER_Capture_1);
CTIMER_StopTimer(CAPTURE_CTIMER);
cap0 = CTIMER_GetCaptureValue(CAPTURE_CTIMER, kCTIMER_Capture_0);
cap1 = CTIMER_GetCaptureValue(CAPTURE_CTIMER, kCTIMER_Capture_1);
s_cap_value = cap1 - cap0;
s_cap1_value[s_cap1_tog] = cap1;
s_cap0_value[s_cap0_tog] = cap0;
s_cap0_tog ^= 0x01;
s_cap1_tog ^= 0x01;
s_done_flag = 1;
}
void ctimer_match0_callback(uint32_t flags)
{
s_done_flag = -1;
}
ctimer_callback_t ctimer_callback_table[] = {
ctimer_match0_callback, NULL, NULL, NULL, NULL, ctimer_capture1_callback, NULL, NULL
};
void capture_init(void)
{
/* CTimer functional clock needs to be greater than or equal to SYSTEM_CLK */
CLOCK_SetClockDiv(kCLOCK_DivCTIMER0, 16); /* Max div 16 96/16=6M */
CLOCK_AttachClk(kFRO_HF_to_CTIMER0);
uint32_t ctimerclk = CLOCK_GetCTimerClkFreq(0);
PRINTF("ctimer0clk=%d\r\n",ctimerclk);
/* Write to GPIO1: Peripheral clock is enabled */
CLOCK_EnableClock(kCLOCK_GateGPIO1);
/* write to INPUTMUX0: Peripheral clock is enabled */
CLOCK_EnableClock(kCLOCK_GateINPUTMUX0);
/* Write to PORT1: Peripheral clock is enabled */
CLOCK_EnableClock(kCLOCK_GatePORT1);
/* GPIO1 peripheral is released from reset */
RESET_ReleasePeripheralReset(kGPIO1_RST_SHIFT_RSTn);
/* INPUTMUX0 peripheral is released from reset */
RESET_ReleasePeripheralReset(kINPUTMUX0_RST_SHIFT_RSTn);
/* CTIMER0 peripheral is released from reset */
RESET_ReleasePeripheralReset(kCTIMER0_RST_SHIFT_RSTn);
/* PORT1 peripheral is released from reset */
RESET_ReleasePeripheralReset(kPORT1_RST_SHIFT_RSTn);
/* INPUTMUX0: Peripheral clock is enabled */
RESET_PeripheralReset(kINPUTMUX0_RST_SHIFT_RSTn);
/* CtimerInp8/9 connect to Timer0Captsel 0/1 */
INPUTMUX_Init(INPUTMUX0);
INPUTMUX_AttachSignal(INPUTMUX0, 0U, kINPUTMUX_CtimerInp8ToTimer0Captsel);
INPUTMUX_AttachSignal(INPUTMUX0, 1U, kINPUTMUX_CtimerInp9ToTimer0Captsel);
const port_pin_config_t port1_8_pin2_config = {/* Internal pull-up/down resistor is disabled */
.pullSelect = kPORT_PullDisable,
/* Low internal pull resistor value is selected. */
.pullValueSelect = kPORT_LowPullResistor,
/* Fast slew rate is configured */
.slewRate = kPORT_FastSlewRate,
/* Passive input filter is disabled */
.passiveFilterEnable = kPORT_PassiveFilterDisable,
/* Open drain output is disabled */
.openDrainEnable = kPORT_OpenDrainDisable,
/* Low drive strength is configured */
.driveStrength = kPORT_LowDriveStrength,
/* Normal drive strength is configured */
.driveStrength1 = kPORT_NormalDriveStrength,
/* Pin is configured as CT_INP8 */
.mux = kPORT_MuxAlt4,
/* Digital input enabled */
.inputBuffer = kPORT_InputBufferEnable,
/* Digital input is not inverted */
.invertInput = kPORT_InputNormal,
/* Pin Control Register fields [15:0] are not locked */
.lockRegister = kPORT_UnlockRegister};
/* PORT1_8 (pin 2) is configured as CT_INP8 */
PORT_SetPinConfig(PORT1, 8U, &port1_8_pin2_config);
const port_pin_config_t port1_9_pin3_config = {/* Internal pull-up/down resistor is disabled */
.pullSelect = kPORT_PullDisable,
/* Low internal pull resistor value is selected. */
.pullValueSelect = kPORT_LowPullResistor,
/* Fast slew rate is configured */
.slewRate = kPORT_FastSlewRate,
/* Passive input filter is disabled */
.passiveFilterEnable = kPORT_PassiveFilterDisable,
/* Open drain output is disabled */
.openDrainEnable = kPORT_OpenDrainDisable,
/* Low drive strength is configured */
.driveStrength = kPORT_LowDriveStrength,
/* Normal drive strength is configured */
.driveStrength1 = kPORT_NormalDriveStrength,
/* Pin is configured as CT_INP9 */
.mux = kPORT_MuxAlt4,
/* Digital input enabled */
.inputBuffer = kPORT_InputBufferEnable,
/* Digital input is not inverted */
.invertInput = kPORT_InputNormal,
/* Pin Control Register fields [15:0] are not locked */
.lockRegister = kPORT_UnlockRegister};
/* PORT1_9 (pin 3) is configured as CT_INP9 */
PORT_SetPinConfig(PORT1, 9U, &port1_9_pin3_config);
ctimer_config_t ctimerConfig;
/*
* ctimerConfig.mode = kCTIMER_TimerMode;
* ctimerConfig.input = kCTIMER_Capture_0;
* ctimerConfig.prescale = 0;
*/
CTIMER_GetDefaultConfig(&ctimerConfig);
CTIMER_Init(CAPTURE_CTIMER, &ctimerConfig);
/*
* Setup the capture, but don't enable the interrupt. And enable the interrupt
* later using CTIMER_EnableInterrupts. Because if enable interrupt usig
* CTIMER_SetupCapture, the CTIMER interrupt is also enabled in NVIC, then default
* driver IRQ handler is called, and callback is involed. To show the capture
* function easily, the default ISR and callback is not used.
*/
CTIMER_SetupCapture(CAPTURE_CTIMER, kCTIMER_Capture_0, kCTIMER_Capture_RiseEdge, false);
CTIMER_SetupCapture(CAPTURE_CTIMER, kCTIMER_Capture_1, kCTIMER_Capture_FallEdge, true);
CTIMER_RegisterCallBack(CAPTURE_CTIMER, &ctimer_callback_table[0], kCTIMER_MultipleCallback);
/*
* Enable the interrupt, so that the kCTIMER_Capture0Flag can be set when
* edge captured.
*/
//CTIMER_EnableInterrupts(CAPTURE_CTIMER, kCTIMER_Capture0InterruptEnable);
//CTIMER_EnableInterrupts(CAPTURE_CTIMER, kCTIMER_Capture1InterruptEnable);
/* match for timeout */
const ctimer_match_config_t match_config = {
.enableCounterReset = true,
.enableCounterStop = true,
.matchValue = 100*6*1000UL,
.outControl = kCTIMER_Output_NoAction,
.enableInterrupt = true,
.outPinInitState = false,
};
CTIMER_SetupMatch(CAPTURE_CTIMER, kCTIMER_Match_0, &match_config);
}
void capture_start(void)
{
s_done_flag = 0;
CTIMER_Reset(CAPTURE_CTIMER);
CTIMER_StartTimer(CAPTURE_CTIMER);
}
/* -1 timeout
* 1 done
* 0 not done
*/
int capture_isdone(void)
{
return s_done_flag;
}
uint32_t capture_get_value(void)
{
return s_cap_value;
}Capture.h
#ifndef CAPTURE_H #define CAPTURE_H void capture_init(void); void capture_start(void); int capture_isdone(void); uint32_t capture_get_value(void); #endif
五. 测试
先获取来回时间,单位us
int get_distance(void)
{
capture_start();
gpio_trig_set(1);
timer_freetimer_delayus(10);
gpio_trig_set(0);
while(1){
int done = capture_isdone();
if(done == -1) {
return -1;
} else if(done == 1) {
return capture_get_value()/6; /* uS */
}
}
}1S采集一次并打印
int main(void)
{
char ch;
/* Init board hardware. */
BOARD_InitHardware();
PRINTF("MCUX SDK version: %s\r\n", MCUXSDK_VERSION_FULL_STR);
PRINTF("hello world.\r\n");
gpio_init();
timer_freetimer_init();
capture_init();
gpio_trig_set(0);
while (1)
{ int distance = get_distance();
if(distance < 0) {
PRINTF("get distance err\r\n");
} else {
PRINTF("distance:%dmm\r\n", distance*340/(2*1000));
}
timer_freetimer_delayus(1000000); }
}打印如下


这里实测手里的手机高度,
官方数据是163mS,实测162mm左右,所以看到准确度还可以。

六.总结
以上实现了超声距离采集,后续就可以驱动屏幕进行显示。
仿真器连不上,尝试暗按ISP按键,再重新上电再连接。
我要赚赏金
