瑞萨单片机论坛
直播中

hehung

8年用户 659经验值
擅长:嵌入式技术
私信 关注

【瑞萨RA4系列开发板体验】8. 超声波测距模块在RA4M2上的应用

之前发帖:

【瑞萨RA4系列开发板体验】1. 新建工程+按键控制LED

【瑞萨RA4系列开发板体验】2. KEIL环境搭建+STLINK调试+FreeRTOS使用

【瑞萨RA4系列开发板体验】3. KEIL下UART实现printf与scanf重定向

【瑞萨RA4系列开发板体验】4. PWM驱动LED

【瑞萨RA4系列开发板体验】5. 硬件IIC驱动OLED显示汉字

【瑞萨RA4系列开发板体验】6. ADC测量摇杆模块偏移量

【瑞萨RA4系列开发板体验】7. 用DAC输出正弦波以及余弦波

前言

本来之前申请试用的时候,打算做一个室内可燃气体检测设备的,但是我的可燃气体传感器居然坏掉了,采集不到ADC数值了,遂只能修改项目,完整了这个测距仪小作品,算是对本次试用的一个作品总结。
手头有一个超声波测距模块,遂使用超声波模块来编写一个举例测试器,本文使用超声波模块US-100是实现了超声波测距的功能。本文实现了一下功能:

  1. 本文基于KEIL开发环境;
  2. 本文使用的除超声波功能之外的功能都是以及之前的发帖内容进一步开发,有需要请参考之前的文章;
  3. 本文实现了超声波模块测距并通过OLED显示距离。

硬件资料

US-100介绍

9.png

通过搜索US-100超声波测距模块的资料,了解到该模块可以通过两种方式进行驱动。

方式一:使用普通GPIO进行驱动Trig触发,然后通过接收echo的反馈波形长度就可以知道超声波测量物体的距离了,该方式需要结合定时器使用,并且自行计算返回距离,使用起来较复杂;

方式二:使用串口,给US-100的TX发送0x55,等待反馈数据,反馈数据为两个单字节数据,第一个字节为距离高位,第二个数据为距离低位,反馈距离为Data0<<8 | Data1, 单位是mm,详细资料见下图。0.png

使用串口模式还可以获取超声波模块的温度,这个温度是用来补偿超声波数据,用来进行校准的,我们也可以通过发送0x50获取内部温度数据,温度数据为单字节,获取的数值-45就是真实的温度。

01.png

为了设计的便捷性,本文使用了串口的模式,使用串口模式需要将US-100后边的跳线帽连接上。8.png

单片机硬件

确定使用UART连接之后,查看一下数据手册,看看还有没有串口可以供我们使用。我们可以使用SCI0的TXD0以及RXD0.1.png

RASC配置

打开RASC,过程不在赘述。

在Pins页面配置SCI0,如下图:2.png

在Stacks页面下配置串口,方式同我之前发布的帖子。

【瑞萨RA4系列开发板体验】3. KEIL下UART实现printf与scanf重定向

不再赘述,详见配置页面。

3.png

4.png

代码设计

配置完成之后点击生成配置代码,然后开始代码设计。

过程比较简单,与我之前的文章类似,我新建了app_us100.c自己app_us100.h,逻辑详见代码。

app_us100.c

在该文件中实现了如下功能函数:

  1. US100相关引脚初始化(及UART初始化);
  2. 开始测距函数;
  3. 获取测的距离函数;
  4. 开始获取温度函数;
  5. 获取温度值函数;
/*
@hehung
2022-12-10
*/
#include "hal_data.h"
#include "app_dac.h"
#include <stdio.h>

static volatile uint8_t uart0_send_mode = 0;
static volatile bool uart0_send_complete_flag = false;
static volatile bool uart0_recv_complete_flag = false;
static volatile uint32_t uart0_recv_char = '\0';
static volatile uint8_t uart0_recv_cnt = 0U;

// callback function for uart0
void uart0_notification(uart_callback_args_t * p_args)
{
	if (p_args->event == UART_EVENT_TX_COMPLETE)
	{
		uart0_send_complete_flag = true;
	}
	else if (p_args->event == UART_EVENT_RX_CHAR)
	{
		if (uart0_send_mode == 0U)	
		{
			++uart0_recv_cnt;
			if (uart0_recv_cnt == 2U)
			{
				uart0_recv_cnt = 0U;
				uart0_recv_char = (uart0_recv_char << 8U) | p_args->data;
				uart0_recv_complete_flag = true;
			}
			else
			{
				uart0_recv_char = p_args->data;
			}			
		}
		else
		{
			uart0_recv_char = p_args->data;
			uart0_recv_complete_flag = true;
		}
	}
}

// Uart0 initialize
void US100_Init(void)
{
	fsp_err_t err = FSP_SUCCESS;
	
	/* Open the transfer instance with initial configuration. */
    err = R_SCI_UART_Open(&g_uart0_ctrl, &g_uart0_cfg);
    assert(FSP_SUCCESS == err);
}

/* Start US100 distance test */
void US100_StartDistance(void)
{
	fsp_err_t err = FSP_SUCCESS;
	uint8_t send_ch;
	
	/* 0x50 is command for get the distance from US-100 */
	send_ch = 0x55U;

	uart0_send_mode = 0U;
	err = R_SCI_UART_Write(&g_uart0_ctrl, (uint8_t *)&send_ch, 1);
	if(FSP_SUCCESS != err) 
		__BKPT();
}

/* Start US100 temperature test */
void US100_StartTemperature(void)
{
	fsp_err_t err = FSP_SUCCESS;
	uint8_t send_ch;
	
	/* 0x50 is command for get the temperature from US-100 */
	send_ch = 0x50U;

	uart0_send_mode = 1U;
	err = R_SCI_UART_Write(&g_uart0_ctrl, (uint8_t *)&send_ch, 1);
	if(FSP_SUCCESS != err) 
		__BKPT();
}

/* Read the distance from US100 */
uint8_t US100_ReadDistance(uint16_t *distance)
{
	if ((true == uart0_recv_complete_flag) && (0U == uart0_send_mode))
	{
//		printf ("Distance reveived is %d\n", uart0_recv_char);
		*distance = uart0_recv_char & 0xFFFFU;
		uart0_recv_complete_flag = false;
		return 1;
	}
	else
	{
		return 0;
	}
	
}

/* Read the temperature from US100 */
uint8_t US100_ReadTemperature(uint8_t *temp)
{
	if ((true == uart0_recv_complete_flag) && (1U == uart0_send_mode))
	{
//		printf ("Temperature reveived is %d\n", uart0_recv_char);
		*temp = uart0_recv_char & 0xFFU;
		uart0_recv_complete_flag = false;
		return 1;
	}
	else
	{
		return 0;
	}
}

app_us100.h

/*
@hehung
2022-12-10
*/

#ifndef APP_US100_H_
#define APP_US100_H_

#include "stdint.h"

extern void US100_Init(void);
extern void US100_StartDistance(void);
extern void US100_StartTemperature(void);
extern uint8_t US100_ReadDistance(uint16_t *distance);
extern uint8_t US100_ReadTemperature(uint8_t *temp);

#endif

主函数

主函数中实现了相关模块初始化,发送测距函数开始距离测试,获取测试结果,发送温度获取命令,获取温度值,并通过OLED显示,每500ms更新一次数据。

uint16_t dist;
uint8_t temp;

void hal_entry(void)
{
	char disp_str[16];
	
	/* Initialize the uart for implement the 'printf' and 'scanf' */
	Uart_Init();
	/* Initialize the os and some tasks */
//	Task_Create();
	/* Initialize the I2c */
	I2c_Init();
	/* Initialize the OLED */
	OLED_Init();
	/* Initialize the ADC */
	Adc_Init();
	/* initialize the US100 - Ultrasonic module */
	US100_Init();
	
	OLED_ShowString(12, 0, (const uint8_t*)"R7FA4M2AD3CFP", 16, 1);
//    OLED_ShowHzStringRow(32, 24, (const char*)"电子发烧友", 1);
    OLED_ShowString(0, 16, (const uint8_t*)"elecfans", 16, 1);
	OLED_ShowString(64, 16, (const uint8_t*)"|hehung", 16, 1);
    OLED_Refresh_Gram();
	
	while (1) 
	{
		US100_StartDistance();
		while (!US100_ReadDistance(&dist)) 
		{
			R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MICROSECONDS);
		}
			
		US100_StartTemperature();
		while (!US100_ReadTemperature(&temp)) 
		{
			R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MICROSECONDS);
		}
		
		sprintf(disp_str, "Dis:%03dmm", (dist));
		OLED_ShowString(0, 32, (const uint8_t*)disp_str, 16, 1);
		sprintf(disp_str, "Temp:%03dC", ((int)temp - 45));
		OLED_ShowString(0, 48, (const uint8_t*)disp_str, 16, 1);
		OLED_Refresh_Gram();
			
		R_BSP_SoftwareDelay(500, BSP_DELAY_UNITS_MILLISECONDS);
	}

#if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
#endif
}

效果演示

5.png

我测试了20cm以及10cm,发现测试存在一定的误差,距离越远,误差越大。

20cm测试结果,可以看到,测试结果为21cm左右,存在1cm的误差。

6.png

10cm测试结果,可以看到,测试结果误差较大,但是还是偏大。

7.png

从测试结果可以看到,获取的温度数值明显不对,当前室内温度也就十几度,但是温度测试出来是20多度,估计是温度的影响导致测试距离存在一定的误差,但是在测试精度要求不是很严重的场合,超声波测距还是可以的,或者自己外接温度传感器对距离进行补偿。

测试验证视频见末尾

演示

更多回帖

发帖
×
20
完善资料,
赚取积分