linux下串口编程设置函数---------set_opt(fd1,115200,8,'N'1)--------------------

本文介绍了一个用于串口配置的函数set_opt,详细说明了如何通过该函数设置串口的波特率、数据位、校验位及停止位等关键参数。

open /dev/ttys0, 设备文件之后,得到文件描述符, 对串口进行设置。

/**
*串口设置函数:例(fd1, 115200, 8, 'N', 1);
*参数:
*fd:串口设备节点
*nSpeed:波特率
*nBits:数据位
*nEvent:校验位
*nStop:停止位
*返回值:成功 -- 0
*		 失败 -- -1
*/
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
	struct termios newtio,oldtio;
	if  ( tcgetattr( fd,&oldtio)  !=  0) { 
		perror("SetupSerial 1");
		return -1;
	}
	bzero( &newtio, sizeof( newtio ) );
	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;
	tcflush(fd,TCIFLUSH);
	if((tcsetattr(fd,TCSANOW,&newtio))!=0)
	{
		perror("com set error");
		return -1;
	}
//	printf("set done!\n\r");
	return 0;
}


#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <unistd.h> #include <termios.h> #include <sys/select.h> int set_uart(int fd, int nSpeed, int nBits, char nEvent, int nStop); uint8_t crc8(const uint8_t *data, uint16_t length); void DDSM_ID_Set(uint8_t id); void DDSM_ID_find(); void DDSM_Mode_Set(uint8_t id,uint8_t mode); void DDSM_shache(uint8_t id); static int _server_ioctl_init(const char *gpio_index); static int _server_ioctl_on(const char *gpio_index); static int _server_ioctl_off(const char *gpio_index); static int _server_ioctl_exit(const char *gpio_index); static int rs485_zj (); static int rs485_fa (uint8_t id,const uint8_t *data,size_t length); static int rs485_shou (); void DDsm_feedback(); void clear_input_buffer(); #define SERVER_GPIO_INDEX_1119” // RS485-1 流控引脚编号 #define SERVER_GPIO_INDEX_2 “120” // RS485-2 流控引脚编号 const char default_path_1[] = “/dev/ttyS4”; // RS485-1 对应的串口 const char default_path_2[] = “/dev/ttyS7”; // RS485-2 对应的串口 //// 用于获取单个字符输入 int get_char_without_enter() { struct termios oldt, newt; int ch; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); ch = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); return ch; } // CRC8校验函数 uint8_t crc8(const uint8_t *data, uint16_t length) { unsigned int i; unsigned char crc = 0x00; while(length–) { crc ^= *data++; for (i = 0; i < 8; i++) { if (crc & 0x01) crc = (crc >> 1) ^ 0x8C; else crc >>= 1; } } return crc; } //电机id设置,设置ID时请保证总线上只有一个电机,每次上电只允许设置一次,电机接收到5次ID设置指令后进行设置。 void DDSM_ID_Set(uint8_t id) { int i; uint8_t data[10]={0xAA,0x55,0x53,id,0x00,0x00,0x00,0x00,0x00,0x00}; for(i=0;i<5;i++) { int fd1; fd1 = open(default_path_1, O_RDWR); if (fd1 < 0) { perror(default_path_1); exit(-1); } if (set_uart(fd1, 115200, 8, 'n', 1)) { printf("Set UART for RS485-1 error\n"); close(fd1); exit(-1); } if (_server_ioctl_init(SERVER_GPIO_INDEX_1)) { printf("GPIO initialization error\n"); close(fd1); exit(-1); } _server_ioctl_on(SERVER_GPIO_INDEX_1); // RS485-1设置为发送模式 write(fd1, data, strlen(data)); // RS485-1发送数据 printf("Data contents:\n"); for (int j = 0; j < sizeof(data) / sizeof(data[0]); j++) { printf("data[%d] = 0x%02X\n", j, data[j]); } usleep(10000); // 等待10ms _server_ioctl_exit(SERVER_GPIO_INDEX_1); close(fd1); } } //电机ID查询,查询ID时请保证总线上只有一个电机 void DDSM_ID_find() { int i; uint8_t crc; uint8_t data1[9]={0xC8,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; crc=crc8(data1, sizeof(data1)); uint8_t data[10]={0xC8,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,crc}; int fd1; fd1 = open(default_path_1, O_RDWR); if (fd1 < 0) { perror(default_path_1); exit(-1); } if (set_uart(fd1, 115200, 8, 'n', 1)) { printf("Set UART for RS485-1 error\n"); close(fd1); exit(-1); } if (_server_ioctl_init(SERVER_GPIO_INDEX_1)) { printf("GPIO initialization error\n"); close(fd1); exit(-1); } _server_ioctl_on(SERVER_GPIO_INDEX_1); // RS485-1设置为发送模式 write(fd1, data, sizeof(data)); // RS485-1发送数据 printf("Data contents:\n"); for (int j = 0; j < sizeof(data); j++) { printf("data[%d] = 0x%02X\n", j, data[j]); } usleep(10000); // 等待10ms _server_ioctl_exit(SERVER_GPIO_INDEX_1); close(fd1); } //电机反馈 void DDsm_feedback() { rs485_shou (); } //电机刹车 void DDSM_shache(uint8_t id) { uint8_t data1[9]={id,0x64,0x00,0x00,0x00,0x00,0x00,0XFF,0x00}; uint8_t crc; crc=crc8(data1,sizeof(data1)); uint8_t data[10]={id,0x64,0x00,0x00,0x00,0x00,0x00,0XFF,0x00,crc}; rs485_fa(id,data,sizeof(data)); usleep(10000); } //电机运行,id:电机编号 ctrl_value:在当面模式下的控制值 speedUp_Time:加速时间 lock_Car:刹车 0xff生效 速度环模式下使用 void DDSM_run(uint8_t id,int16_t ctrl_value,uint8_t speedUp_Time,uint8_t lock_Car) { uint8_t crc; uint8_t data1[9]={id,0x64,(uint8_t)(ctrl_value>>8),(uint8_t)(ctrl_value),0x00,0x00,speedUp_Time,lock_Car,0x00}; crc=crc8(data1,sizeof(data1)); uint8_t data[10]={id,0x64,(uint8_t)(ctrl_value>>8),(uint8_t)(ctrl_value),0x00,0x00,speedUp_Time,lock_Car,0x00,crc}; rs485_fa(id,data,sizeof(data)); usleep(10000); } //电机模式设置 0x01:设定为电流环 0x02:设定为速度环 0x03:设定为置环 void DDSM_Mode_Set(uint8_t id,uint8_t mode) { uint8_t data[10]={id,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,mode}; rs485_fa(id,data,sizeof(data)); } // 初始化GPIO流控引脚 static int _server_ioctl_init(const char *gpio_index) { int fd; char path[256]; fd = open(“/sys/class/gpio/export”, O_WRONLY); if (fd < 0) return 1; write(fd, gpio_index, strlen(gpio_index)); close(fd); snprintf(path, sizeof(path), "/sys/class/gpio/gpio%s/direction", gpio_index); fd = open(path, O_WRONLY); // 打开文件 //fd = open("/sys/class/gpio/gpio" gpio_index "/direction", O_WRONLY); if (fd < 0) return 2; write(fd, "out", strlen("out")); close(fd); return 0; } // 设置GPIO流控引脚为高电平 static int _server_ioctl_on(const char *gpio_index) { int fd; char path[256]; snprintf(path, sizeof(path), “/sys/class/gpio/gpio%s/value”, gpio_index); fd = open(path, O_WRONLY); // 打开文件 if (fd < 0) return 1; write(fd, "1", 1); close(fd); return 0; } // 设置GPIO流控引脚为低电平 static int _server_ioctl_off(const char *gpio_index) { int fd; char path[256]; snprintf(path, sizeof(path), “/sys/class/gpio/gpio%s/value”, gpio_index); fd = open(path, O_WRONLY); // 打开文件 if (fd < 0) return 1; write(fd, "0", 1); close(fd); return 0; } // 关闭GPIO流控引脚 static int _server_ioctl_exit(const char *gpio_index) { int fd; fd = open(“/sys/class/gpio/unexport”, O_WRONLY); if (fd < 0) return 1; write(fd, gpio_index, strlen(gpio_index)); close(fd); return 0; } // 配置串口函数 int set_uart(int fd, int nSpeed, int nBits, char nEvent, int nStop) { struct termios opt; tcflush(fd, TCIOFLUSH); tcgetattr(fd, &opt); opt.c_cflag &= (~CBAUD); opt.c_cflag &= (~PARENB); opt.c_iflag &= (~ICRNL); opt.c_lflag &= (~ECHO); switch (nSpeed) { case 2400: cfsetspeed(&opt, B2400); break; case 4800: cfsetspeed(&opt, B4800); break; case 9600: cfsetspeed(&opt, B9600); break; case 38400: cfsetspeed(&opt, B38400); break; case 115200: cfsetspeed(&opt, B115200); break; default: return -1; } switch (nBits) { case 7: opt.c_cflag |= CS7; break; case 8: opt.c_cflag |= CS8; break; default: return -1; } switch (nEvent) { case 'n': case 'N': opt.c_cflag &= (~PARENB); break; case 'o': case 'O': opt.c_cflag |= PARODD; break; case 'e': case 'E': opt.c_cflag |= PARENB; opt.c_cflag &= (~PARODD); break; default: return -1; } switch (nStop) { case 1: opt.c_cflag &= ~CSTOPB; break; case 2: opt.c_cflag |= CSTOPB; break; default: return -1; } tcsetattr(fd, TCSANOW, &opt); return 0; } //两路rs485互检函数 static int rs485_zj () { int fd1, fd2; int res1, res2; char buf[1024] = “456998\n”; char buf1[1024] = “1214438\n”; char buf2[1024], buf3[1024]; int i; // 打开RS485-1串口 fd1 = open(default_path_1, O_RDWR); if (fd1 < 0) { perror(default_path_1); exit(-1); } // 打开RS485-2串口 fd2 = open(default_path_2, O_RDWR); if (fd2 < 0) { perror(default_path_2); close(fd1); exit(-1); } // 配置RS485-1串口参数 if (set_uart(fd1, 115200, 8, 'n', 1)) { printf("Set UART for RS485-1 error\n"); close(fd1); close(fd2); exit(-1); } // 配置RS485-2串口参数 if (set_uart(fd2, 115200, 8, 'n', 1)) { printf("Set UART for RS485-2 error\n"); close(fd1); close(fd2); exit(-1); } // 初始化GPIO流控引脚 if (_server_ioctl_init(SERVER_GPIO_INDEX_1) || _server_ioctl_init(SERVER_GPIO_INDEX_2)) { printf("GPIO initialization error\n"); close(fd1); close(fd2); exit(-1); } for (i = 0; i < 10; i++) { // RS485-1发送数据,RS485-2接收数据 _server_ioctl_on(SERVER_GPIO_INDEX_1); // RS485-1设置为发送模式 _server_ioctl_off(SERVER_GPIO_INDEX_2); // RS485-2设置为接收模式 write(fd1, buf, strlen(buf)); // RS485-1发送数据 printf("RS485-1 Send data: %s\n", buf); usleep(100000); // 等待10ms memset(buf2, 0, sizeof(buf2)); res2 = read(fd2, buf2, sizeof(buf2)); // RS485-2接收数据 if (res2 > 0) { printf("RS485-2 Received data (%d bytes): %s\n", res2, buf2); } else { printf("No data received on RS485-2\n"); } // RS485-2发送数据,RS485-1接收数据 _server_ioctl_off(SERVER_GPIO_INDEX_1); // RS485-1设置为接收模式 _server_ioctl_on(SERVER_GPIO_INDEX_2); // RS485-2设置为发送模式 write(fd2, buf1, strlen(buf1)); // RS485-2发送数据 printf("RS485-2 Send data: %s\n", buf1); usleep(100000); // 等待10ms memset(buf3, 0, sizeof(buf3)); res1 = read(fd1, buf3, sizeof(buf3)); // RS485-1接收数据 if (res1 > 0) { printf("RS485-1 Received data (%d bytes): %s\n", res1, buf3); } else { printf("No data received on RS485-1\n"); } printf("Cycle index is %d\n", i); usleep(10000); // 等待10ms } // 退出GPIO流控引脚 _server_ioctl_exit(SERVER_GPIO_INDEX_1); _server_ioctl_exit(SERVER_GPIO_INDEX_2); // 关闭串口 close(fd1); close(fd2); return 0; } //两路rs485发送函数 static int rs485_fa (uint8_t id,const uint8_t *data,size_t length) { int fd1, fd2; int res1, res2; int i; if (id==1) { // 打开RS485-1串口 fd1 = open(default_path_1, O_RDWR); if (fd1 < 0) { perror(default_path_1); exit(-1); } // 配置RS485-1串口参数 if (set_uart(fd1, 115200, 8, 'n', 1)) { printf("Set UART for RS485-1 error\n"); close(fd1); exit(-1); } // 初始化GPIO流控引脚 if (_server_ioctl_init(SERVER_GPIO_INDEX_1)) { printf("GPIO initialization error\n"); close(fd1); exit(-1); } _server_ioctl_on(SERVER_GPIO_INDEX_1); // RS485-1设置为发送模式 write(fd1, data, length); // RS485-1发送数据 printf("RS485-1 send contents:\n"); for ( i = 0; i < length; i++) { printf("data[%d] = 0x%02X\n", i, data[i]); } usleep(10000); // 等待10ms _server_ioctl_exit(SERVER_GPIO_INDEX_1); close(fd1); }else { // 打开RS485-2串口 fd2 = open(default_path_2, O_RDWR); if (fd2 < 0) { perror(default_path_2); close(fd1); exit(-1); } // 配置RS485-2串口参数 if (set_uart(fd2, 115200, 8, 'n', 1)) { printf("Set UART for RS485-2 error\n"); close(fd2); exit(-1); } // 初始化GPIO流控引脚 if ( _server_ioctl_init(SERVER_GPIO_INDEX_2)) { printf("GPIO initialization error\n"); close(fd2); exit(-1); } _server_ioctl_on(SERVER_GPIO_INDEX_2); // RS485-2设置为发送模式 write(fd2, data, length); // RS485-2发送数据 printf("RS485-2 send contents:\n"); for (int j = 0; j < length; j++) { printf("data[%d] = 0x%02X\n", j, data[j]); } usleep(10000); // 等待10ms _server_ioctl_exit(SERVER_GPIO_INDEX_2); close(fd2); } // 退出GPIO流控引脚 _server_ioctl_exit(SERVER_GPIO_INDEX_1); _server_ioctl_exit(SERVER_GPIO_INDEX_2); // 关闭串口 close(fd1); close(fd2); return 0; } //两路rs485接收函数 static int rs485_shou () { int fd1, fd2; int res1, res2; char buf2[1024], buf3[1024]; int i; // 打开RS485-1串口 fd1 = open(default_path_1, O_RDWR); if (fd1 < 0) { perror(default_path_1); exit(-1); } // 打开RS485-2串口 fd2 = open(default_path_2, O_RDWR); if (fd2 < 0) { perror(default_path_2); close(fd1); exit(-1); } // 配置RS485-1串口参数 if (set_uart(fd1, 115200, 8, 'n', 1)) { printf("Set UART for RS485-1 error\n"); close(fd1); close(fd2); exit(-1); } // 配置RS485-2串口参数 if (set_uart(fd2, 115200, 8, 'n', 1)) { printf("Set UART for RS485-2 error\n"); close(fd1); close(fd2); exit(-1); } // 初始化GPIO流控引脚 if (_server_ioctl_init(SERVER_GPIO_INDEX_1) || _server_ioctl_init(SERVER_GPIO_INDEX_2)) { printf("GPIO initialization error\n"); close(fd1); close(fd2); exit(-1); } _server_ioctl_off(SERVER_GPIO_INDEX_1); // RS485-1设置为接收模式 _server_ioctl_off(SERVER_GPIO_INDEX_2); // RS485-2设置为接收模式 fcntl(fd1, F_SETFL, O_NONBLOCK); fcntl(fd2, F_SETFL, O_NONBLOCK); memset(buf3, 0, sizeof(buf3)); res1 = read(fd1, buf3, sizeof(buf3)); // RS485-1接收数据 if (res1 > 0) { printf("RS485-1 Received data (%d bytes): %s\n", res1, buf3); } else { printf("No data received on RS485-1\n"); } memset(buf2, 0, sizeof(buf2)); res2 = read(fd2, buf2, sizeof(buf2)); // RS485-2接收数据 if (res2 > 0) { printf("RS485-2 Received data (%d bytes): %s\n", res2, buf2); } else { printf("No data received on RS485-2\n"); } usleep(10000); // 退出GPIO流控引脚 _server_ioctl_exit(SERVER_GPIO_INDEX_1); _server_ioctl_exit(SERVER_GPIO_INDEX_2); // 关闭串口 close(fd1); close(fd2); return 0; } // 清空输入缓冲区 void clear_input_buffer() { int ch; while ((ch = getchar()) != ‘\n’ && ch != EOF){}; // 读取并丢弃所有剩余字符 } // 主函数 int main(int argc, char *argv[]) { uint8_t motor_id = 1; // 默认控制电机ID为1 int speed = 0; // 默认速度为0 while (1) { int key = get_char_without_enter(); // 获取键盘输入 switch (key) { case 119: // 前进 speed = 30; printf(“key: %d\n”,key); break; case 115: // 后退 speed = -30; printf("key: %d\n",key); break; case 98: // 刹车 printf("key: %d\n",key); break; case 113: // 退出 printf("key: %d\n",key); goto exit_program; // 跳出循环并退出程序 break; default: printf("Unknown key: %d \n", key); break; } usleep(100000); } exit_program: return 0; } 该代码如何实现键盘控制电机执行不同操作并修改代码来实现这个操作
最新发布
05-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值