Linux串口应用编程——STM32MP157

文章介绍了如何在Linux系统下通过替换设备树文件来开启串口,特别是串口8。使用structtermios结构体和相关函数如tcgetattr、tcsetattr来设置行规程,包括波特率、数据位、停止位等。还提供了一个实现串口回环的示例代码,用于测试串口配置是否正确。
摘要由CSDN通过智能技术生成

替换设备树文件

挂载boot分区:

mount /dev/mmcblk2 /boot

拷贝新的设备树文件到boot分区

cp /mnt/stm32mp157c-100ask-512d-lcd-v1.dtb /boot

reboot重启,查询设备节点

ls /dev/ttySTM*

发现新的设备节点ttySTM3

/dev/ttySTM0  /dev/ttySTM1  /dev/ttySTM3

设备树开启串口8的原理就是通过Pinctrl指定芯片连接的扩展板引脚,涉及到驱动方面的知识,具体查看视频:修改设备树,开启串口驱动

串口API

在 Linux 系统中,操作设备的统一接口就是:open/ioctl/read/write。
对于 UART,又在 ioctl 之上封装了很多函数,主要是用来设置行规程。所以对于 UART,编程的套路就是:

  • open;
  • 设置行规程,比如波特率、数据位、停止位、检验位、RAW 模式、一有数据就返回;
  • read/write;

在这里插入图片描述

行规程采用默认模式时,需要按下enter键才能执行上传

设置行规程

struct termios 结构体

在这里插入图片描述
该结构体主要用于与驱动进行通信的载体

行规程函数

函数名作用
tcgetattrget terminal attributes,获得终端的属性
tcsetattrset terminal attributes,修改终端参数
tcflush清空终端未完成的输入/输出请求及数据
cfsetispeedsets the input baud rate,设置输入波特率
cfsetospeedsets the output baud rate,设置输出波特率
cfsetspeed同时设置输入、输出波特率

这些函数在名称上有一些惯例:

  • tc:terminal contorl
  • cf: control flag

串口应用——回环

接线
在这里插入图片描述
代码:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>

/* set_opt(fd,115200,8,'N',1) */
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
	struct termios newtio,oldtio;
	//获取默认的参数,保存在oldtio结构体中
	if ( tcgetattr( fd,&oldtio) != 0) { 
		perror("SetupSerial 1");
		return -1;
	}
	
	bzero( &newtio, sizeof( newtio ) );
	newtio.c_cflag |= CLOCAL | CREAD; 
	newtio.c_cflag &= ~CSIZE; 

	newtio.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
	newtio.c_oflag  &= ~OPOST;   /*Output*/

	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;
	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[VMIN]  = 1;  /* 读数据时的最小字节数: 没读到这些数据我就不返回! */
	newtio.c_cc[VTIME] = 0; /* 等待第1个数据的时间: 
	                         * 比如VMIN设为10表示至少读到10个数据才返回,
	                         * 但是没有数据总不能一直等吧? 可以设置VTIME(单位是10秒)
	                         * 假设VTIME=1,表示: 
	                         *    10秒内一个数据都没有的话就返回
	                         *    如果10秒内至少读到了1个字节,那就继续等待,完全读到VMIN个数据再返回
	                         */

	tcflush(fd,TCIFLUSH);
	//通过该结构体设置行规程
	if((tcsetattr(fd,TCSANOW,&newtio))!=0)
	{
		perror("com set error");
		return -1;
	}
	//printf("set done!\n");
	return 0;
}

int open_port(char *com)
{
	int fd;
	//fd = open(com, O_RDWR|O_NOCTTY|O_NDELAY);
	fd = open(com, O_RDWR|O_NOCTTY);//O_NOCTTY表示不设置为控制终端,不会接收控制信号
    if (-1 == fd){
		return(-1);
    }
	
	  if(fcntl(fd, F_SETFL, 0)<0) /* 设置串口为阻塞状态,若第三个参数为FNDELAY则表示没有数据返回0*/
	  {
			printf("fcntl failed!\n");
			return -1;
	  }
  
	  return fd;
}


/*
 * ./serial_send_recv <dev>
 */
int main(int argc, char **argv)
{
	int fd;
	int iRet;
	char c;

	/* 1. open */

	/* 2. setup 
	 * 115200,8N1
	 * RAW mode
	 * return data immediately
	 */

	/* 3. write and read */
	
	if (argc != 2)
	{
		printf("Usage: \n");
		printf("%s </dev/ttySAC1 or other>\n", argv[0]);
		return -1;
	}

	fd = open_port(argv[1]);
	if (fd < 0)
	{
		printf("open %s err!\n", argv[1]);
		return -1;
	}

	iRet = set_opt(fd, 115200, 8, 'N', 1);
	if (iRet)
	{
		printf("set port err!\n");
		return -1;
	}

	printf("Enter a char: ");
	while (1)
	{
		scanf("%c", &c);
		iRet = write(fd, &c, 1);
		iRet = read(fd, &c, 1);
		if (iRet == 1)
			printf("get: %02x %c\n", c, c);
		else
			printf("can not get data\n");
	}

	return 0;
}

参考博文:
Linux串口—struct termios结构体
Linux串口编程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值