#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_1 “119” // 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;
}
该代码如何实现键盘控制电机执行不同操作并修改代码来实现这个操作
最新发布