硬件资源
EEPROM 24C02的设备地址为:0x1010001* ;
硬件接口说明
引脚名称开发者可在硬件资源图中查看,也可在智慧车载模块背面查看。
引脚名称 |
功能描述 |
ECHO |
测距脉宽输出,高电平的宽度代表超声波往返时间 |
TRIG |
测距触发,输入10us的高电平脉冲,开始测距 |
BUZZER |
蜂鸣器控制线,推荐3KHz的方波信号 |
LED_Warning |
LED控制线,低电平有效 |
I2C_SCL |
I2C时钟信号线 |
I2C-SDA |
I2C数据信号线 |
GND |
电源地引脚 |
3V3 |
3.3V电源输入引脚 |
GND |
电源地引脚 |
硬件设计
模块整体硬件电路如上图所示,电路中包含了E53接口连接器,EEPROM存储器、超声波处理电路,声光报警电路。
超声波测距芯片,选用CS-100A,其是一款工业级超声波测距芯片,内部集成超声波发射电路,超声波接收电路,数字处理电路等,单片即可完成超声波测距,测距结果通过脉宽的方式进行输出。
CS100A配合使用40KHz的开放式超声波探头,在超声波发射端并联一个电阻R2到地和8MHz的晶振,即可实现高性能的测距功能,电阻R2的大小决定了超声波测量的距离。
三极管Q1为NPN管,基极为高电平时,三极管才能够导通,蜂鸣器需PWM波驱动,人耳可识别的频率范围为20Hz-20KHz,故PWM频率需在该范围内,我们默认使用3KHz的PWM波驱动。
硬件连接
小凌派开发板与模块均带有防呆设计,故很容易区分安装方向,直接将模块插入到开发板的E53母座接口上即可,
程序设计
API分析
GPIO接口
GPIO接口文档
PWM接口
PWM接口文档
LiteOS信号量
LiteOS信号量接口文档
主要代码分析
初始化代码分析
初始化GPIO
初始化GPIO0_PC4和GPIO0_PA5为GPIO。首先通过 LzGpioInit()初始化GPIO引脚,其次通过 LzGpioSetDir()设置GPIO为输出模式,最后通过 LzGpioSetVal()设置输出高电平/低电平。
/***************************************************************
* 函数名称: e53_iv01_init_gpio
* 说 明: 初始化GPIO
* 参 数: 无
* 返 回 值: 无
***************************************************************/
static void e53_iv01_init_gpio()
{
/* Trig引脚设置为GPIO输出模式 */
PinctrlSet(E53_IV01_TRIG_GPIO, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP);
LzGpioInit(E53_IV01_TRIG_GPIO);
LzGpioSetDir(E53_IV01_TRIG_GPIO, LZGPIO_DIR_OUT);
E53_IV01_TRIG_Clr();
/* LED_WARNING灯引脚设置为GPIO输出模式 */
PinctrlSet(E53_IV01_LED_WARNING_GPIO, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP);
LzGpioInit(E53_IV01_LED_WARNING_GPIO);
LzGpioSetDir(E53_IV01_LED_WARNING_GPIO, LZGPIO_DIR_OUT);
e53_iv01_led_warning_set(0);
}
初始化GPIO中断
初始化GPIO0_PA2为GPIO。首先通过 LzGpioInit()初始化GPIO引脚,其次通过 LzGpioSetDir()设置GPIO为输入模式,最后通过 LzGpioRegisterIsrFunc()设置该引脚为中断模式,触发模式为边沿触发(即上升沿+下降沿都可触发)。
/***************************************************************
* 函数名称: e53_iv01_init_interrupt
* 说 明: 初始化GPIO中断
* 参 数: 无
* 返 回 值: 无
***************************************************************/
static void e53_iv01_init_interrupt()
{
LzI2cInit(0, 400000);
/* 创建信号量 */
LOS_SemCreate(0, &m_task_sem);
/* Echo引脚设置为GPIO输出模式 */
PinctrlSet(E53_IV01_ECHO0_GPIO, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP);
LzGpioInit(E53_IV01_ECHO0_GPIO);
LzGpioSetDir(E53_IV01_ECHO0_GPIO, LZGPIO_DIR_IN);
LzGpioRegisterIsrFunc(E53_IV01_ECHO0_GPIO, GPIO_INT_EDGE_BOTH, e53_iv01_interrupt_echo_func, NULL);
}
初始化PWM
初始化GPIO0_PC7为GPIO。首先通过 PwmIoInit()初始化PWM配置,最后通过 LzPwmInit()初始化PWM配置id。
/***************************************************************
* 函数名称: e53_iv01_init_pwm
* 说 明: 初始化PWM
* 参 数: 无
* 返 回 值: 无
***************************************************************/
static unsigned int e53_iv01_init_pwm()
{
/* 初始化pwm */
PinctrlSet(E53_IV01_BUZZER_GPIO, MUX_FUNC2, PULL_DOWN, DRIVE_KEEP);
if (PwmIoInit(m_buzzer_config) != LZ_HARDWARE_SUCCESS)
{
printf("%s, %d: PwmIoInit failed
", __func__, __LINE__);
return __LINE__;
}
if (LzPwmInit(E53_IV01_PWM_IO) != LZ_HARDWARE_SUCCESS)
{
printf("%s, %d: LzPwmInit failed
", __func__, __LINE__);
return __LINE__;
}
return 0;
}
车载测距流程代码分析
首先,初始化相关变量,使能GPIO中断,并控制TRIG引脚往E53模块发送一个至少10usec的高电平,通知E53模块开始工作。具体代码如下所示:
m_echo_info.flag = EECHO_FLAG_CAPTURE_RISE;
LzGpioEnableIsr(E53_IV01_ECHO0_GPIO);
LOS_Msleep(1);
e53_iv01_send_trig();
其次,等待信号量(该信号量最长等待时间为200msec)。具体代码如下所示:
LOS_SemPend(m_task_sem, LOS_MS2Tick(200));
在GPIO中断处理函数中记录E53模块用ECHO引脚发送过来的一个高电平时间宽度(该高电平的时间宽度为超声波来回的时间宽度)。具体实现方式为:
上升沿触发时,记录系统时钟(即定时器5)的当前节拍数,修改触发状态;
下降沿出发时,记录系统时钟(即定时器5)的当前节拍数,修改触发状态,释放信号量。
具体代码如下:
/***************************************************************
* 函数名称: e53_iv01_interrupt_echo_func
* 说 明: GPIO中断处理函数,通过中断捕获定时器计数器当前值
* 参 数:
* @arg,
* 返 回 值: 无
***************************************************************/
static VOID e53_iv01_interrupt_echo_func(VOID *arg)
{
if (m_echo_info.flag == EECHO_FLAG_CAPTURE_RISE)
{
/* 获取上升沿的定时器计数器当前值 */
m_echo_info.time_rise = *m_ptimer5_current_value_low;
m_echo_info.flag = EECHO_FLAG_CAPTURE_FALL;
}
else if (m_echo_info.flag == EECHO_FLAG_CAPTURE_FALL)
{
/* 获取下降沿的定时器计数器当前值 */
m_echo_info.time_fall = *m_ptimer5_current_value_low;
m_echo_info.flag = EECHO_FLAG_CAPTURE_SUCCESS;
LOS_SemPost(m_task_sem);
}
else
{
/* 什么都不做 */
}
}
然后禁用GPIO中断,判断中断状态判断E53模块是否采集成功。具体代码如下:
/* 禁用GPIO中断 */
LzGpioDisableIsr(E53_IV01_ECHO0_GPIO);
if (m_echo_info.flag == EECHO_FLAG_CAPTURE_SUCCESS)
{/* 如果是采集成功,则计算距离 */
if (m_echo_info.time_rise <= m_echo_info.time_fall)
{
time_diff = m_echo_info.time_fall - m_echo_info.time_rise;
}
else
{
time_diff = 0xFFFFFFFF - m_echo_info.time_rise + m_echo_info.time_fall + 1;
}
e53_iv01_calc_cm(time_diff, ECHO_TIMER_FREQ, distance_cm);
return 1;
}
else
{
printf("%s, %d: flag(%d) is error!
", __func__, __LINE__, m_echo_info.flag);
return 0;
}
最后,根据上升沿和下降沿的节拍数差计算距离。其中,系统时钟为40MHz,超声波速度为340米/秒,高电平时间宽度为超声波的往返之和,所以实际距离 = 节拍数差 / 40MHz / 340(米/秒) / 2(往返2次)。具体计算代码如下:
/***************************************************************
* 函数名称: e53_iv01_calc_cm
* 说 明: 计算超声波测距
* 参 数:
* @time:节拍数
* @freq:节拍频率,以Hz为单位
* @meter:距离差,以厘米为单位
* 返 回 值: 无
***************************************************************/
static inline void e53_iv01_calc_cm(uint32_t time, uint32_t freq, float *cmeter)
{
float f_time = (float)time;
float f_freq = (float)freq;
/* 距离 = 时间差 * 340米/秒 / 2(超时波来回2次) * 100厘米/米 */
*cmeter = f_time / f_freq * 170.0 * 100.0;
}
编译调试
修改 BUILD.gn 文件
修改 vendor/lockzhiner/lingpi/sample 路径下 BUILD.gn 文件,指定 e53_iv01_example 参与编译。
"e53_intelligent_vehicle_01",
在主目录下输入编译命令。
hb build -f
运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,并请使用带有LCD屏幕显示如下:
distance cm: 23.92
distance cm: 23.89
distance cm: 23.90
原作者:王小彬 Gitee