RS485 half-duplex test code
/*************************************************************************
> File Name: serial.c
> Author: lancz
> Mail:
> Created Time: 2019年09月26日 星期四 20时18分14秒
************************************************************************/
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <termios.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <linux/serial.h>
typedef struct{
int speed;
int name;
}SysHalUartSpeedMap_t;
const SysHalUartSpeedMap_t SysHalUartSpeedMap[] = {
{ B1000000, 1000000 },
{ B500000, 500000 },
{ B460800, 460800 },
{ B230400, 230400 },
{ B115200, 115200 },
{ B38400, 38400 },
{ B19200, 19200 },
{ B9600, 9600 },
{ B4800, 4800 },
{ B2400, 2400 },
{ B1200, 1200 },
};
static void sysHalUartSetSpeed(int fd, int speed)
{
uint8_t i;
struct termios opt;
if(0 != tcgetattr(fd,&opt)) return;
for(i = 0; i < sizeof(SysHalUartSpeedMap)/sizeof(SysHalUartSpeedMap[0]); i++){
if(speed == SysHalUartSpeedMap[i].name){
tcflush(fd,TCIOFLUSH);
printf("set speed = %d\n",speed);
cfsetispeed(&opt,SysHalUartSpeedMap[i].speed);
cfsetospeed(&opt,SysHalUartSpeedMap[i].speed);
if(0 != tcsetattr(fd,TCSANOW,&opt)){
printf("tcset attr error \n");
return ;
}
tcflush(fd,TCIOFLUSH);
break;
}
}
}
/**
* @brief:sysHalUartSetParity
*
* @param: fd
* @param: bits
* @param: stopBit
* @param: parity
*
* @return
*
* @author:
* @date:2018-05-10
*/
static int sysHalUartSetParity(int fd, int bits, int stopBit, char parity)
{
struct termios opt;
if(0 != tcgetattr(fd,&opt)) return -1;
printf("configure uart, bit = %d,stopbit = %d, parity = %d\n",bits,stopBit,parity);
/* config bit */
opt.c_cflag &= ~CSIZE;
switch(bits){
case 7:
opt.c_cflag |= CS7;
break;
case 8:
opt.c_cflag |= CS8;
break;
default:
printf("Error uart bit size.\n"); return -1;
}
/* config parity */
switch(parity){
case 'n':
case 'N':
opt.c_cflag &= ~PARENB;
opt.c_iflag &= ~INPCK;
break;
case 'o':
case 'O':
opt.c_cflag |= (PARODD | PARENB);
opt.c_iflag |= INPCK;
break;
case 'e':
case 'E':
opt.c_cflag |= PARENB;
opt.c_cflag &= ~PARODD;
opt.c_iflag |= INPCK;
break;
case 's':
case 'S':
opt.c_cflag &= ~PARENB;
opt.c_iflag &= ~CSTOPB;
break;
default:
printf("error parity");
return -1;
}
/* config stopbit */
switch(stopBit){
case 1:
opt.c_cflag &= ~CSTOPB;
break;
case 2:
opt.c_cflag |= CSTOPB;
break;
default:
printf("error stop bit config.\n");
return -1;
}
opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
opt.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
opt.c_oflag &= ~OPOST;
tcflush(fd,TCIFLUSH);
opt.c_cc[VTIME] = 5;
opt.c_cc[VMIN] = 0;
#if defined(ENABLE_HW_CTS)
opt.c_cflag |= CRTSCTS;
#endif
if(0 != tcsetattr(fd, TCSANOW, &opt)){
printf("Error config uart attr.\n");
return -1;
}
return 0;
}
void main(void)
{
fd_set fds;
struct timeval tv;
char temp[512] = {0};
int fd = open("/dev/ttyS2",O_RDWR | O_NOCTTY | O_NDELAY);
sysHalUartSetSpeed(fd, 9600);
sysHalUartSetParity(fd, 8, 1,'E');
system("echo 85 > /sys/class/gpio/unexport");
system("echo 85 > /sys/class/gpio/export");
system("echo out > /sys/class/gpio/PC21/direction");
system("echo 0 > /sys/class/gpio/PC21/value");
tv.tv_sec = 0;
tv.tv_usec = 5000;
while(1) {
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (select(fd + 1, &fds, NULL, NULL, &tv) < 0) {
perror("select error");
}
if (FD_ISSET(fd, &fds)) {
int n = read(fd, temp, sizeof(temp));
if (n > 0) {
for (int i = 0; i < n; i++)
printf("%02X ", temp[i]);
printf("\n");
}
}
system("echo 1 > /sys/class/gpio/PC21/value;sync");
write(fd, "hello world", 11);
usleep(11 * 1000 * 8);
system("echo 0 > /sys/class/gpio/PC21/value;sync");
}
}
小记:
(1) 当在arm linux 上运行PC端的程序时会报类似编译的错误。
(2) rs485半双工通讯在没有硬件自动控制同步的情况下,需要由应用程序来同步。