分享自己编写的RT_thread 串口应用超声波测距验证

/*
    硬件接口说明:
    PC10     ------> UART4_TX
    PC11     ------> UART4_RX 

    Y401(US-100) 接口定义:
		模式选择:串口模式(有跳帽)
		1  Pin: 接 VCC 电源(供电范围 2.4V~5.5V)。
    2  Pin: 当为 UART 模式时, 接外部电路 UART 的 TX 端;当为电平触发模式时,接外部电路的 Trig 端。
		3  Pin: 当为 UART 模式时, 接外部电路 UART 的 RX 端;当为电平触发模式时,接外部电路的 Echo 端。
		4  Pin: 接外部电路的地
		5  Pin: 接外部电路的地
		
	  by:貌似稿手2021.02.25  
*/

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <rtdbg.h>
#include "common.h"
#define SAMPLE_UART_NAME       "uart4"


/* 用于接收消息的信号量 */
static struct rt_semaphore rx_sem;
static rt_device_t serial;

static void clearRxBuff(void)
{
	 uint8_t buf = 0;			 
   while(rt_device_read(serial,0,&buf,1));
	 rx_sem.value=0;
}

static void UartSend(u8 * buf,u16 sendlen)
{
    rt_device_write(serial, 0, buf, sendlen);
}

/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    /* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
    rt_sem_release(&rx_sem);
    return RT_EOK;
}

//超声波测距离
//timeout: 超时等待时间,单位毫秒
//单位   :毫米
u16 ReadDistanceValue(u16 timeout)
{
     char buff[10];
	   u16 index,i;
	   rt_memset(buff,0,sizeof(buff));
     buff[0]=0x55;//触发命令
     clearRxBuff();
     UartSend((u8*)buff,1);//测试距离工作

		 if(rt_sem_take(&rx_sem, timeout) == RT_EOK)//有数据回复
		 {
				 while(rt_sem_take(&rx_sem, 50)!=-RT_ETIMEOUT);//超时判断接收一帧数据包
				 index=rt_device_read(serial, RT_NULL, buff, 64); 
		 
				 //数据分析处理一帧数据
//				 rt_kprintf("Y401 RX:");
//				 for(i=0;i<index;i++)
//					 rt_kprintf("%02X",buff[i]);
//				 rt_kprintf("\r\n");

			   if(index==2) 
				 return (buff[0]*256+buff[1]);//计算距离
				 
			}
			else LOG_E("Y401 no data rx failed!!");
			
	    return RT_ERROR;
}


//超声波测温度,温感电阻
//timeout: 超时等待时间,单位毫秒
//单位   :°C
int ReadTemperatureValue(u16 timeout)
{
     char buff[10];
	   u16 index,i;
	   rt_memset(buff,0,sizeof(buff));
     buff[0]=0x50;//触发命令
     clearRxBuff();
     UartSend((u8*)buff,1);//测试距离工作

		 if(rt_sem_take(&rx_sem, timeout) == RT_EOK)//有数据回复
		 {
				 while(rt_sem_take(&rx_sem, 50)!=-RT_ETIMEOUT);//超时判断接收一帧数据包
				 index=rt_device_read(serial, RT_NULL, buff, 64); 
		 
//				 //数据分析处理一帧数据
//				 rt_kprintf("Y401 RX:");
//				 for(i=0;i<index;i++)
//					 rt_kprintf("%02X",buff[i]);
//				 rt_kprintf("\r\n");

			   if(index==1) 
				 return (buff[0]-45);//计算温度
				 
			}
			else LOG_E("Y401 no data rx failed!!");
			
	    return RT_ERROR;
}

//超声波串口测距模块
static int y401_uart_init(void)
{
    rt_err_t ret = RT_EOK;

	  struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;  /* 初始化配置参数 */
    /* 查找系统中的串口设备 */
    serial = rt_device_find(SAMPLE_UART_NAME);
    if (!serial)
    {
        rt_kprintf("find y401_uart failed!\n");
        return RT_ERROR;
    }

		/* step2:修改串口配置参数 */
		config.baud_rate = BAUD_RATE_9600;        //修改波特率为 115200
		config.data_bits = DATA_BITS_8;             //数据位 8
		config.stop_bits = STOP_BITS_1;             //停止位 1
		config.bufsz     = 64;                     //修改缓冲区 buff size 为 128
		config.parity    = PARITY_NONE;             //无奇偶校验位		

    /* step3:控制串口设备。通过控制接口传入命令控制字,与控制参数 */
    rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);		
		
    /* 初始化信号量 */
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    /* 以中断接收及轮询发送模式打开串口设备 */
    rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
		
    /* 设置接收回调函数 */
    rt_device_set_rx_indicate(serial, uart_input);
   
		rt_kprintf("y401_uart init finish!\r\n");
    return ret;
}
INIT_DEVICE_EXPORT(y401_uart_init);

//距离检测一次命令导出
static void Detection_Distance(void)
{
	u16 times=100;
	while(times--)
	{
		rt_kprintf("times  : %d \r\n",times);
	  rt_thread_mdelay(100);
		rt_kprintf("distance   : %d mm \r\n",ReadDistanceValue(1000));
	}
}


MSH_CMD_EXPORT(Detection_Distance, Y401 US_100 Detection Distance);


//PID算法
//超时波偏差值,偏差次数
static volatile u16 csb_offval=0;
//超声波人体移动检测,偏差4次以上认为有人通过
static void csb_check_thread(void *parameter)
{
	volatile u16 oldval=0;
	volatile u16 nowval=0;
	volatile u16 val=0;
	
	oldval=ReadDistanceValue(1000);
	csb_offval=200;//可以远程配置,可以动态调节,pid算法
	while(1)
	{
		val=ReadDistanceValue(1000);
		rt_kprintf("distance   : %d mm \r\n",val);
		rt_thread_mdelay(100);
		if(val!=RT_ERROR)
		{
			//if((val-oldval)>csb_offval || (val-oldval)<csb_offval )//偏差值
			if((oldval-val)>csb_offval  )//偏差值
			{
				  LOG_W("CSB_OFFSET:%d",csb_offval );
					//beep_ON();
				  rt_event_send(commen_event, WRITE_EVENT_CSB);
					rt_thread_mdelay(2000);
				  oldval=ReadDistanceValue(1000);
			}
			else oldval=val;
		}
		else
		{
			LOG_E ("ReadDistanceValue err\r\n");
		}
		
	}
}

static rt_thread_t csb_tid = RT_NULL;
void csb_tid_thread_init(void)
{
	csb_tid = rt_thread_create("csb",csb_check_thread, RT_NULL,1024,12, 10);
	
  if (csb_tid != RT_NULL)
		rt_thread_startup(csb_tid);
}
INIT_DEVICE_EXPORT(csb_tid_thread_init);


//偏差值配置
static int coffset(int argc, char** argv)
{
	  int temp=0;
		temp = strtoul(argv[1], 0, 10);
	  csb_offval=temp;
	  LOG_W("temp=%d\n",temp);

    return 0;	
}
MSH_CMD_EXPORT(coffset, ID config   );


 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值