智能车上位机与下位机通信的例子
2015-10-28 15:28
465 查看
智能车的主板(上位机)是小车控制模块的核心,负责路况采集、行驶行为决策等重要功能。下位机(单片机)是小车执行模块的关键,负责直接操作电机、舵机等,来控制行驶的速度和方向。
通常需要上位机给下位机发送命令,如何在二者之间实现通信成为一个研究话题。本文给出了一种串口通信的方法,来实现这个功能。
上位机使用C语言编写,关键代码如下:/**
*@brief 打开串口设备
*@param Dev 类型 char* 打开串口的设备名或者目录
*@return fd 类型 int 打开成功返回设备id,否则返回-1
*/
int openDev( char* Dev )
{
int fd = open( Dev, O_RDWR );//以可读写的方式打开串口
//fd = open( Dev,O_RDWR | 0_NOCTTY | O_NONBLOCK );
//| O_NOCTTY | O_NDELAY
if( -1 == fd )
{
perror( "Can't Open Serial Port" );
return -1;
}
else
return fd;
}
/**
*@brief 设置串口通信速率
*@param fd 类型 int 打开串口的文件句柄
*@param speed 类型 int 串口速度
*@return void
*/
void set_speed( int fd, int speed )
{
int i;
int status;
struct termios Opt;
tcgetattr( fd, &Opt );
for( i = 0; i < sizeof( speed_arr ) / sizeof( int ); i++ )
{
if( speed == name_arr[ i ] )
{
tcflush( fd, TCIOFLUSH );
cfsetispeed( &Opt, speed_arr[ i ] );
cfsetospeed( &Opt, speed_arr[ i ] );
status = tcsetattr( fd, TCSANOW, &Opt );
if( status != 0 )
{
perror( "tcsetattr fd" );
return;
}
tcflush( fd, TCIOFLUSH );
}
}
}
/**
*@brief 设置串口数据位,停止位和效验位
*@param fd 类型 int 打开的串口文件句柄
*@param databits 类型 int 数据位 取值 为 7 或者8
*@param stopbits 类型 int 停止位 取值为 1 或者2
*@param parity 类型 int 效验类型 取值为N,E,O,,S
*/
int set_Parity( int fd, int databits, int stopbits, int parity )
{
struct termios options;
if( tcgetattr( fd, &options ) != 0 )
{
perror( "SetupSerial 1" );
return FALSE;
}
options.c_cflag &= ~CSIZE;
options.c_lflag &= ~( ICANON | ECHO | ECHOE | ISIG ); /*Input*/
options.c_oflag &= ~OPOST; /*Output*/
switch( databits ) /*设置数据位数*/
{
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
fprintf( stderr, "Unsupported data size\n" );
return FALSE;
}
switch( parity )
{
case 'n':
case 'N':
options.c_cflag &= ~PARENB; /* Clear parity enable */
options.c_iflag &= ~INPCK; /* Enable parity checking */
break;
case 'o':
case 'O':
options.c_cflag |= ( PARODD | PARENB ); /* 设置为奇效验*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'e':
case 'E':
options.c_cflag |= PARENB; /* Enable parity */
options.c_cflag &= ~PARODD; /* 转换为偶效验*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'S':
case 's': /*as no parity*/
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default:
fprintf( stderr, "Unsupported parity\n" );
return FALSE;
}
/* 设置停止位*/
switch( stopbits )
{
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
fprintf( stderr, "Unsupported stop bits\n" );
return FALSE;
}
/* Set input parity option */
if( parity != 'n' )
options.c_iflag |= INPCK;
tcflush( fd, TCIFLUSH );
options.c_cc[ VTIME ] = 0; /* 设置超时0 seconds*/
options.c_cc[ VMIN ] = 1; /* define the minimum bytes data to be readed*/
if( tcsetattr( fd, TCSANOW, &options ) != 0 )
{
perror( "SetupSerial 3" );
return FALSE;
}
return TRUE;
}
本文使用的智能车下位机为Arduino单片机,使用相关语言编写,关键代码如下:
//接收上位机传送的信息串(实现上下通信)
void readSerial() {
if(Serial.available()) {
isDisconnect = 0;
if((ReadVal[0] = Serial.read()) == 152) {
for(int i = 1; Serial.available() && i <= 3; ++i) {
ReadVal[i] = Serial.read();
}
if(ReadVal[3] == 225) {
speedVal = ReadVal[1];
directionVal = ReadVal[2];
if(speedVal == 0 || speedVal >= 190 || speedVal <= 210
|| speedVal >= 160 || speedVal <= 170) {
motorSpeed = speedVal;
}
else {
motorSpeed = 0;
}
servoDirection = directionVal;
if(directionVal > 125) {
servoDirection = 125;
}
else if(directionVal < 55) {
servoDirection = 55;
}
}
}
}
else {
isDisconnect++;
if(isDisconnect > 10) {
motorSpeed = 0;
servoDirection = 90;
}
}
}
至此,上位机可以通过串口的方式给下位机发命令了。
通常需要上位机给下位机发送命令,如何在二者之间实现通信成为一个研究话题。本文给出了一种串口通信的方法,来实现这个功能。
上位机使用C语言编写,关键代码如下:/**
*@brief 打开串口设备
*@param Dev 类型 char* 打开串口的设备名或者目录
*@return fd 类型 int 打开成功返回设备id,否则返回-1
*/
int openDev( char* Dev )
{
int fd = open( Dev, O_RDWR );//以可读写的方式打开串口
//fd = open( Dev,O_RDWR | 0_NOCTTY | O_NONBLOCK );
//| O_NOCTTY | O_NDELAY
if( -1 == fd )
{
perror( "Can't Open Serial Port" );
return -1;
}
else
return fd;
}
/**
*@brief 设置串口通信速率
*@param fd 类型 int 打开串口的文件句柄
*@param speed 类型 int 串口速度
*@return void
*/
void set_speed( int fd, int speed )
{
int i;
int status;
struct termios Opt;
tcgetattr( fd, &Opt );
for( i = 0; i < sizeof( speed_arr ) / sizeof( int ); i++ )
{
if( speed == name_arr[ i ] )
{
tcflush( fd, TCIOFLUSH );
cfsetispeed( &Opt, speed_arr[ i ] );
cfsetospeed( &Opt, speed_arr[ i ] );
status = tcsetattr( fd, TCSANOW, &Opt );
if( status != 0 )
{
perror( "tcsetattr fd" );
return;
}
tcflush( fd, TCIOFLUSH );
}
}
}
/**
*@brief 设置串口数据位,停止位和效验位
*@param fd 类型 int 打开的串口文件句柄
*@param databits 类型 int 数据位 取值 为 7 或者8
*@param stopbits 类型 int 停止位 取值为 1 或者2
*@param parity 类型 int 效验类型 取值为N,E,O,,S
*/
int set_Parity( int fd, int databits, int stopbits, int parity )
{
struct termios options;
if( tcgetattr( fd, &options ) != 0 )
{
perror( "SetupSerial 1" );
return FALSE;
}
options.c_cflag &= ~CSIZE;
options.c_lflag &= ~( ICANON | ECHO | ECHOE | ISIG ); /*Input*/
options.c_oflag &= ~OPOST; /*Output*/
switch( databits ) /*设置数据位数*/
{
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
fprintf( stderr, "Unsupported data size\n" );
return FALSE;
}
switch( parity )
{
case 'n':
case 'N':
options.c_cflag &= ~PARENB; /* Clear parity enable */
options.c_iflag &= ~INPCK; /* Enable parity checking */
break;
case 'o':
case 'O':
options.c_cflag |= ( PARODD | PARENB ); /* 设置为奇效验*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'e':
case 'E':
options.c_cflag |= PARENB; /* Enable parity */
options.c_cflag &= ~PARODD; /* 转换为偶效验*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'S':
case 's': /*as no parity*/
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default:
fprintf( stderr, "Unsupported parity\n" );
return FALSE;
}
/* 设置停止位*/
switch( stopbits )
{
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
fprintf( stderr, "Unsupported stop bits\n" );
return FALSE;
}
/* Set input parity option */
if( parity != 'n' )
options.c_iflag |= INPCK;
tcflush( fd, TCIFLUSH );
options.c_cc[ VTIME ] = 0; /* 设置超时0 seconds*/
options.c_cc[ VMIN ] = 1; /* define the minimum bytes data to be readed*/
if( tcsetattr( fd, TCSANOW, &options ) != 0 )
{
perror( "SetupSerial 3" );
return FALSE;
}
return TRUE;
}
本文使用的智能车下位机为Arduino单片机,使用相关语言编写,关键代码如下:
//接收上位机传送的信息串(实现上下通信)
void readSerial() {
if(Serial.available()) {
isDisconnect = 0;
if((ReadVal[0] = Serial.read()) == 152) {
for(int i = 1; Serial.available() && i <= 3; ++i) {
ReadVal[i] = Serial.read();
}
if(ReadVal[3] == 225) {
speedVal = ReadVal[1];
directionVal = ReadVal[2];
if(speedVal == 0 || speedVal >= 190 || speedVal <= 210
|| speedVal >= 160 || speedVal <= 170) {
motorSpeed = speedVal;
}
else {
motorSpeed = 0;
}
servoDirection = directionVal;
if(directionVal > 125) {
servoDirection = 125;
}
else if(directionVal < 55) {
servoDirection = 55;
}
}
}
}
else {
isDisconnect++;
if(isDisconnect > 10) {
motorSpeed = 0;
servoDirection = 90;
}
}
}
至此,上位机可以通过串口的方式给下位机发命令了。
相关文章推荐
- 深入分析Visual C++进行串口通信编程的详解
- C#串口通信程序实例详解
- 基于Arduino+LabVIEW的多路数据采集系统
- 基于Arduino+LabVIEW的串口控制LED亮灭
- 基于Protues的Arduino学习笔记01-Arduino UNO实验板设计
- 《Arduino与LabVIEW开发实战》-前言
- Arduino(一)
- 51单片机的中断整理
- 时钟+温度+遥控设置,综合时钟例子
- 温度传感器+I2C+串口+PC上位机(pyserial)例子
- 51单片机中data,idata,xdata,pdata的区别
- 什么叫51单片机最小系统
- 用串口连接GSM手机发送和接收短消息,在应用程序中如何编程实现?
- MCU之心路分享
- 按键led
- 单片机学会释放CPU
- 单片机无线串行接口电路设计
- 单片机无线串行接口电路设计
- 单片机系统中的红外通信接口
- 单片机系统中的红外通信接口