/*
硬件接口说明:
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 );