Elfboard-ELF开发板 Linux学习笔记(六)—— 应用编程篇 串口通信(下)

Elfboard-ELF开发板 Linux学习笔记(六)—— 应用编程篇 串口通信(下)

三、串口通信配置

3.1 打开串口

第一步:打开串口设备,使用 open()函数打开串口的设备节点文件,得到文件描述符:

    int fd;
    fd = open("/dev/ttymxc2", O_RDWR | O_NOCTTY);
    if (0 > fd) {
    perror("open error");
    return -1;
    }

第二步:获取当前配置参数 tcgetattr()
第三步:写配置

struct termios newtio, oldtio;
if (tcgetattr(fd, &oldtio) != 0)        // 获取当前配置参数并保存
{
    perror("tcgetattr");
    return -1;
}
bzero(&newtio, sizeof(newtio));         // 清零配置参数
newtio.c_cflag |= CLOCAL | CREAD;       // 开启本地连接,开启接收
newtio.c_cflag &= ~CSIZE;               // 清除数据位设置

if((tcsetattr(fd, TCSANOW, &newtio)) != 0) // 写配置
{
    perror("com set error");
    return -1;
}

第四步:串口读写

3.2 配置串口

  • 串口结构体
/*串口参数结构体 */
typedef struct
{
    unsigned long baudrate; /*波特率 600~4000000*/
    unsigned char data_bit; /*数据位5/6/7/8*/
    unsigned char stop_bit; /*停止位 1/2*/
    unsigned char check;    /*校验方式 'N':无校验,'O':奇校验,'E':偶校验*/
    unsigned char hardware;/*硬件流控*/
} struct_tty_param;

写三个函数进行配置

  • 1.串口配置函数
  • 2.串口发送函数
  • 3.串口接收函数

四、串口通信程序

4.1 串口配置函数

/*
 * @description     : 串口参数设置
 * @param - speed   : 波特率
 * @param - bits    : 数据位
 * @param - stop    : 停止位
 * @param - check   : 校验方式
 * @param - hardware: 硬件流控
 * @return		    : 执行结果
 */
int func_set_opt(int fd, unsigned long speed, unsigned char bits, unsigned char stop, unsigned char check, unsigned char hardware)
{
    struct termios newtio, oldtio;
	/*保存原先串口设置*/
    if (tcgetattr(fd, &oldtio) != 0)	//通过此函数可以我们可以把termios保存在结构变量oldtio;函数原型:int tcgetattr(int fd,struct termois & termios_p);
    {
        perror("tcgetattr");
        return -1;
    }
    bzero(&newtio, sizeof(newtio));
    newtio.c_cflag |= CLOCAL | CREAD; /*用于本地连接和接收使能*/
    newtio.c_cflag &= ~CSIZE;	/*用数据掩码清空数据位设置*/

    switch (bits)
    {
    case 5:
        newtio.c_cflag |= CS5;
        break;
    case 6:
        newtio.c_cflag |= CS6;
        break;
    case 7:
        newtio.c_cflag |= CS7;
        break;
    case 8:
        newtio.c_cflag |= CS8;
        break;
    default:
        newtio.c_cflag |= CS8;
        break;
    }

    switch (check)
    {
    case 'O': //奇校验
        newtio.c_cflag |= PARENB;
        newtio.c_cflag |= PARODD;
        newtio.c_iflag |= INPCK;
        break;
    case 'E': //偶校验
        newtio.c_cflag |= PARENB;
        newtio.c_cflag &= ~PARODD;
        newtio.c_iflag |= INPCK;
        break;
    case 'M': //MARK校验
        newtio.c_cflag |= PARODD;
        newtio.c_cflag |= PARENB;
        newtio.c_cflag |= CMSPAR;
        newtio.c_iflag &= ~INPCK;
        break;
    case 'S': //SPACE校验
        newtio.c_cflag &= ~PARODD;
        newtio.c_cflag |= PARENB;
        newtio.c_cflag |= CMSPAR;
        newtio.c_iflag &= ~INPCK;
        break;
    case 'N': //无校验
        newtio.c_cflag &= ~PARENB;
        break;
    default:
        newtio.c_cflag &= ~PARENB;
        break;
    }

    switch (speed)	//设置波特率
    {
    case 600:
        cfsetispeed(&newtio, B600);
        cfsetospeed(&newtio, B600);
        break;
    case 1200:
        cfsetispeed(&newtio, B1200);
        cfsetospeed(&newtio, B1200);
        break;
    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 19200:
        cfsetispeed(&newtio, B19200);
        cfsetospeed(&newtio, B19200);
        break;
    case 38400:
        cfsetispeed(&newtio, B38400);
        cfsetospeed(&newtio, B38400);
        break;
    case 57600:
        cfsetispeed(&newtio, B57600);
        cfsetospeed(&newtio, B57600);
        break;
    case 115200:
        cfsetispeed(&newtio, B115200);
        cfsetospeed(&newtio, B115200);
        break;
    case 230400:
        cfsetispeed(&newtio, B230400);
        cfsetospeed(&newtio, B230400);
        break;
    case 460800:
        cfsetispeed(&newtio, B460800);
        cfsetospeed(&newtio, B460800);
        break;
    case 500000:
        cfsetispeed(&newtio, B500000);
        cfsetospeed(&newtio, B500000);
        break;
    case 576000:
        cfsetispeed(&newtio, B576000);
        cfsetospeed(&newtio, B576000);
        break;
    case 921600:
        cfsetispeed(&newtio, B921600);
        cfsetospeed(&newtio, B921600);
        break;
    case 1000000:
        cfsetispeed(&newtio, B1000000);
        cfsetospeed(&newtio, B1000000);
        break;
    case 1152000:
        cfsetispeed(&newtio, B1152000);
        cfsetospeed(&newtio, B1152000);
        break;
    default:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    }
    if (stop == 1)
    {
        newtio.c_cflag &= ~CSTOPB;	//将停止位设置成一个bit
    }
    else if (stop == 2)
    {
        newtio.c_cflag |= CSTOPB;	//将停止位设置成两个bit
    }
    if (hardware == 1)
    {
        newtio.c_cflag |= CRTSCTS;
    }
    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");
    return 0;
}

4.2 串口发送函数

/*
 * @description  : 串口发送函数
 * @param - fd   : 文件描述符
 * @param - *p_send_buff: 要发送数据缓冲区首地址
 * @param - count: 要发送数据长度
 * @return		 : 执行结果
 */
int func_send_frame(int fd, const unsigned char *p_send_buff, const int count)
{
    int Result = 0;

    Result = write(fd, p_send_buff, count);
    if (Result == -1)
    {
        perror("write");
        return 0;
    }
    return Result;
}

4.3 串口接收函数

/*
 * @description  : 串口接收函数
 * @param - fd   : 文件描述符
 * @param - *p_receive_buff: 接收数据缓冲区首地址
 * @param - count: 最大接收数据长度
 * @return		 : 执行结果
 */
int func_receive_frame(int fd, unsigned char *p_receive_buff, const int count)
{
    // 阻塞用法
    int nread = 0; 	//存储读取字节数的变量,初始化为0
    fd_set rd;		//监视串口文件描述符是否有数据可读
    int retval = 0;	//用于存储retval函数的返回值
    struct timeval timeout = {0, 500};	//设置select函数的超时时间

    FD_ZERO(&rd);		//用于将rd文件描述符集合清零,方便后续设置监视对象
    FD_SET(fd, &rd);	//将串口文件描述符fd添加到文件描述符集合rd中,以便select监视这个文件描述符是否有可读数据
    memset(p_receive_buff, 0x0, count);		//初始化接收缓冲区
    retval = select(fd + 1, &rd, NULL, NULL, &timeout);		
    switch (retval)
    {
        case 0:
            nread = 0;		//无数据可读
            break;
        case -1:						
            printf("select%s\n", strerror(errno));		//发生错误
            nread = -1;
            break;
        default:
            nread = read(fd, p_receive_buff, count); //读串口		
            break;
    }

    return nread;
}

五、串口程序在开发板中验证

5.1 硬件连接

在这里插入图片描述

使用杜邦线将UART2的TXD和RXD分别连接到UART3的RXD和TXD上。
UART2_RXD-----> _UART3_TXD
UART2_TXD-----> _UART3_RXD
在这里插入图片描述

5.2 串口程序验证

  • 配置编译环境
. /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
  • 查看 CC 变量
    在这里插入图片描述

  • 查看 Makefile

tty_demo: main.o serial.o
    $(CC) -Wall main.o serial.o -o elf1_cmd_serialport

main.o: main.c serial.h
    $(CC) -c -Wall main.c -o main.o

serial.o: serial.c
    $(CC) -c -Wall serial.c -o serial.o

clean:
    $(RM) *.o elf1_cmd_serialport

在这里插入图片描述

  • 编译
make clean
make tty_demo
  • 编译成功后上传文件到开发板
elf@elf-virtual-machine:~/linux_file/1.app_linux/02_elf1_cmd_serialport$ make clean 
rm -f *.o       elf1_cmd_serialport
elf@elf-virtual-machine:~/linux_file/1.app_linux/02_elf1_cmd_serialport$ make tty_demo 
arm-poky-linux-gnueabi-gcc  -march=armv7ve -mfpu=neon  -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/cortexa7hf-neon-poky-linux-gnueabi     -c      -Wall  main.c  -omain.o
arm-poky-linux-gnueabi-gcc  -march=armv7ve -mfpu=neon  -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/cortexa7hf-neon-poky-linux-gnueabi     -c      -Wall  serial.c  -o       serial.o
arm-poky-linux-gnueabi-gcc  -march=armv7ve -mfpu=neon  -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/cortexa7hf-neon-poky-linux-gnueabi     -Wall   main.o serial.o -oelf_serial
elf@elf-virtual-machine:~/linux_file/1.app_linux/02_elf1_cmd_serialport$ scp elf_serial root@192.168.0.232:/home/root/linux_file/serial
elf_serial                                                                                                                                                               100%   19KB   2.1MB/s   00:00    
elf@elf-virtual-machine:~/linux_file/1.app_linux/02_elf1_cmd_serialport$ 

5.3 开发板测试

打开两个窗口
窗口一

窗口二:一秒发送一次数据
1705056139910)

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

君逸~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值