树莓派5访问pin口控制uart-ttl转485
ttl转485
// pi5rw.cpp : Defines the entry point for the application.
//
#include "pi5rw.h"
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#define termios asmtermios
#include <asm/termbits.h>
#undef termios
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/serial.h>
#include <thread>
#include <vector>
int serialSetBaud2(int fd, int baud)
{
struct termios2 tio = { 0 };
if (ioctl(fd, TCGETS2, &tio) < 0)
{
perror("TCGETS2");
return (-1);
}
tio.c_cflag &= ~CRTSCTS; //禁用硬件流控
tio.c_cflag &= ~CBAUD;
tio.c_cflag |= BOTHER;
tio.c_ispeed = baud;
tio.c_ospeed = baud;
ioctl(fd, TCSETS2, &tio);
if (ioctl(fd, TCGETS2, &tio) < 0)
{
perror("TCGETS2");
return (-2);
}
return 0;
}
int serialOpen(const char* device, const int baud)
{
struct termios options;
speed_t myBaud;
int status, fd;
switch (baud)
{
case 50: myBaud = B50; break;
case 75: myBaud = B75; break;
case 110: myBaud = B110; break;
case 134: myBaud = B134; break;
case 150: myBaud = B150; break;
case 200: myBaud = B200; break;
case 300: myBaud = B300; break;
case 600: myBaud = B600; break;
case 1200: myBaud = B1200; break;
case 1800: myBaud = B1800; break;
case 2400: myBaud = B2400; break;
case 4800: myBaud = B4800; break;
case 9600: myBaud = B9600; break;
case 19200: myBaud = B19200; break;
case 38400: myBaud = B38400; break;
case 57600: myBaud = B57600; break;
case 115200: myBaud = B115200; break;
case 230400: myBaud = B230400; break;
case 460800: myBaud = B460800; break;
case 500000: myBaud = B500000; break;
case 576000: myBaud = B576000; break;
case 921600: myBaud = B921600; break;
case 1000000: myBaud = B1000000; break;
case 1152000: myBaud = B1152000; break;
case 1500000: myBaud = B1500000; break;
case 2000000: myBaud = B2000000; break;
case 2500000: myBaud = B2500000; break;
case 3000000: myBaud = B3000000; break;
case 3500000: myBaud = B3500000; break;
case 4000000: myBaud = B4000000; break;
default:
return -2;
}
if ((fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1)
return -1;
fcntl(fd, F_SETFL, O_RDWR);
// Get and modify current options:
tcgetattr(fd, &options);
cfmakeraw(&options);
cfsetispeed(&options, myBaud);
cfsetospeed(&options, myBaud);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_oflag &= ~OPOST;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 100; // Ten seconds (100 deciseconds)
tcsetattr(fd, TCSANOW, &options);
ioctl(fd, TIOCMGET, &status);
status |= TIOCM_DTR;
status |= TIOCM_RTS;
ioctl(fd, TIOCMSET, &status);
usleep(10000); // 10mS
return fd;
}
void serialSetAttr(int fd, uint8_t DataBits = '8', uint8_t Parity = 'N', uint8_t StopBits = '2')
{
struct termios options = { 0 };
tcgetattr(fd, &options); // Read current options
// 启动接收器,能够从串口中读取输入数据
options.c_cflag |= CLOCAL;
options.c_cflag |= CREAD;
options.c_cflag &= ~CRTSCTS; //禁用硬件流控
options.c_cflag &= ~CSIZE; // Mask out size
options.c_cflag |= CS8; // Or in 8-bits
options.c_cflag &= ~(PARENB | INPCK); // Disable Parity - even by default
options.c_cflag |= CSTOPB; // Stop bits
// 设置数据位
switch (DataBits)
{
case '5': options.c_cflag |= CS5; break;
case '6': options.c_cflag |= CS6; break;
case '7': options.c_cflag |= CS7; break;
case '8': options.c_cflag |= CS8; break;
default: options.c_cflag |= CS8; break;//默认数据位为8
}
// 设置校验方式
switch (Parity)
{
// 无校验
case 'n':
case 'N':
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
break;
// 偶校验
case 'e':
case 'E':
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_iflag |= INPCK;
break;
// 奇校验
case 'o':
case 'O':
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
options.c_iflag |= INPCK;
// 设置为空格
case 's':
case 'S':
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
// 默认无校验
default:
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
break;
}
// 设置停止位
switch (StopBits)
{
case '1': options.c_cflag &= ~CSTOPB; break;
case '2': options.c_cflag |= CSTOPB; break;
default: options.c_cflag &= ~CSTOPB; break;
}
tcflush(fd, TCIFLUSH);//handle unrecevie char
tcsetattr(fd, TCSANOW, &options); // Set new options
}
std::vector<uint8_t> ToFrame(const std::vector<uint8_t>& vInData)
{
uint16_t crc = 0x0000;
std::vector<uint8_t> frame(vInData.begin(), vInData.end());
frame.at(1) = frame.size();
for (auto i = 0; i < frame.size() - 2; i++)
{
crc += frame.at(i);
}
frame.at(frame.size() - 2) = ((uint8_t*)&crc)[0];
frame.at(frame.size() - 1) = ((uint8_t*)&crc)[1];
return frame;
}
void serialSend(int fd, const std::vector<uint8_t>& data/* = {}*/)
{
int nLen = 0;
auto vData = ToFrame(data);
vData.insert(vData.begin(), 0x00);
serialSetBaud2(fd, 19200);
nLen = write(fd, vData.data(), vData.size());
serialSetBaud2(fd, 250000);
}
int test()
{
int fd = 0;
// gpio 使用硬件串口
if ((fd = serialOpen("/dev/ttyAMA0", 115200)) < 0)
{
printf("serialOpen error(%d)\n", errno);
return (-1);
}
//设置为非阻塞模式
//fcntl(fd, F_SETFL, O_NONBLOCK);
serialSetAttr(fd);
serialSetBaud2(fd, 250000);
std::thread([&]()
{
while (true) {
int result;
if (ioctl(fd, FIONREAD, &result) == -1 || result == 0)
{
usleep(1000 * 50);
continue;
}
unsigned char buffer[1024] = { 0 };
int ret = read(fd, buffer, sizeof(buffer));
if (ret > 0) {
printf("read:");
//依次将读取到的数据输出到日志
for (int i = 0; i < ret; ++i)
printf(" %02x", buffer[i]);
////当收到数据时,再将收到的数据原样发送
//int n = write(fd, buffer, ret);
//if (n != ret)
// printf("send fail!\n");
////当收到0xFF时,跳出循环
//if (buffer[0] == 0xFF)
// break;
continue;
}
else {
//没收到数据时,休眠50ms,防止过度消耗cpu
usleep(1000 * 50);
}
}
}
).detach();
while (true)
{
getchar();
{
serialSend(fd, { 0x80, 0x00, 0x06, 0xD0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
}
}
close(fd);
return 0;
}
int main(int argc, char ** argv)
{
std::cout << "Hello CMake." << std::endl;
test();
return 0;
}
配置/boot/config.txt
[all]
usb_max_current_enable=1
dtoverlay=uart0,ctsrts
#dtoverlay=uart0-pi5,ctsrts