收集数据集的时候需要给数据打时间戳,数据是从单片机上用蓝牙传输到电脑上的,所以需要测试一下传输的延迟,在此做一下记录。
用到的设备
单片机:STM32F103
蓝牙模块:HC-05,两个
USB转TTL:一个
PC:Ubuntu16.04系统
主要思想
从PC端通过蓝牙发送一个数据给单片机,单片机再发送回来,计算时间差除以2,记录多次取平均。
蓝牙和电脑通过USB转TTL连接,与串口等效;和单片机串口直连,也和单片机串口等效。
两个蓝牙模块需要配置为主从机,教程参考:
https://blog.csdn.net/zx3517288/article/details/52291027
单片机的程序主要是串口接收,然后再发送就好了。
PS:蓝牙模块连接串口1,程序和串口通信相同
//中断处理
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
{
//把寄存器的数据原封不动发回去
USART_SendData(USART1, USART1->DR);
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
}
else if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
//清除接收标志位
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
//使能发送中断
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
}
USART_ClearITPendingBit(USART1,USART_IT_ORE);
}
主函数比较简单,系统初始化之后就while(1){}
就好。
主要实现的功能是:
#include
#include
long timestamp()
{
struct timeval tv;
std::string time_string;
gettimeofday(&tv, NULL);
long time_long = tv.tv_sec*1000 + tv.tv_usec/1000;
return time_long;
}
配置参考了网上的代码,整理如下:
usart.cpp
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "main.h"
//初始化
void usart_init()
{
struct termios signal_usart;
struct sigaction saio; /* definition of signal action */
/* open the device to be non-blocking (read will return immediatly) */
usart_0 = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (usart_0 <0)
{
perror(MODEMDEVICE);
std::cout << "Can not open " << MODEMDEVICE << std::endl;
exit(-1);
}
//设置中断处理函数,就是接收到数据后会执行的函数,定义在后面
saio.sa_handler = bluetooth_receive;
sigemptyset(&saio.sa_mask);
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
fcntl(usart_0, F_SETOWN, getpid());//allow the process to receive SIGIO
fcntl(usart_0, F_SETFL, FASYNC);//恢复串口的状态为阻塞状态,用于等待串口数据的读入
set_opt(signal_usart,usart_0,115200,8,'N',1);
}
int set_opt(struct termios newtio,int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
/*步骤一,设置字符大小*/
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
/*设置数据位*/
switch( nBits )
{
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
}
/*设置奇偶校验位*/
switch( nEvent )
{
case 'O': //奇数
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'E': //偶数
newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
break;
case 'N': //无奇偶校验位
newtio.c_cflag &= ~PARENB;
break;
}
/*设置波特率*/
switch( nSpeed )
{
case 2400:
cfsetispeed(&newtio, B2400);
cfsetospeed(&newtio, B2400);
break;
case 4800:
cfsetispeed(&newtio, B4800);
cfsetospeed(&newtio, B4800);
break;
case 9600:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
case 115200:
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
break;
case 460800:
cfsetispeed(&newtio, B460800);
cfsetospeed(&newtio, B460800);
break;
default:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
}
/*设置停止位*/
if( nStop == 1 )
newtio.c_cflag &= ~CSTOPB;
else if ( nStop == 2 )
newtio.c_cflag |= CSTOPB;
/*设置等待时间和最小接收字符*/
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 0;
//使用原始模式,如果以字符串形式接收下面两行可以去掉
newtio.c_lflag &= ~(ICANON | ECHO | ECHOE |ISIG);
newtio.c_oflag &= ~OPOST;
/*处理未接收字符*/
tcflush(fd,TCIFLUSH);
/*激活新配置*/
if((tcsetattr(fd,TCSANOW,&newtio))!=0)
{
perror("com set error");
return -1;
}
printf("Serial port set done!\n");
return 0;
}
usart.h
#ifndef USART_HPP
#define USART_HPP
#include
#include
#include
#include
void usart_init();
int set_opt(struct termios newtio,int fd,int nSpeed, int nBits, char nEvent, int nStop);
extern int usart_0;
#endif // USART_HPP
主函数:
main.cpp
//
// Created by chenyr on 19-10-12.
//
#include "main.h"
int8_t test_data = 0x55; //用于测试的数据
long time_send, time_rece;
std::vector delays;
int main()
{
delays.reserve(1000);
usart_init();
bluetooth_send(test_data); //发送
float average = 0;
while(delays.size() < 1000) //发送1000+次
{
}
//计算平均时间
for (int i = 0; i < delays.size(); i++)
average += delays[i];
average /= delays.size();
std::cout << "Average delay time: " << average << std::endl;
}
void bluetooth_send(int8_t temp)
{
time_send = timestamp();
write(usart_0, &temp, sizeof(int8_t));
}
//串口初始化时绑定的处理函数
void bluetooth_receive(int status)
{
int8_t buf;
std::string receive_str;
read(usart_0,&buf, sizeof(int8_t));
if (buf == test_data)
{
long time_rece = timestamp();
std::cout << "delay time: " << (time_rece - time_send)/2.0 << std::endl;
delays.push_back((float)(time_rece - time_send)/2.0f);
}
else
{
std::cout << "receive wrong data: " << buf << std::endl;
}
bluetooth_send(test_data);
}
main.h
//
// Created by chenyr on 19-10-12.
//
#ifndef MAIN_H
#define MAIN_H
#include
#include "usart.h"
#include "timestamp.h"
#include
#include
void bluetooth_send(int8_t temp);
void bluetooth_receive(int status);
#endif
在蓝牙收发模块的直线距离不超过2m的情况下做了3组测试,距离逐渐增加,得到的结果如下:
在测试的时候发现Ubuntu和STM32的大小端并不一样,所以如果发送16位以上的数据,接收到的数据高低位是反的,所以我测试的时候用的是8位的数据(int8_t)。