做网站不错的公司,dns服务器 域名不存在时 跳转到指定网站,电话营销系统,oa办公系统网站开发本文目录 前述一、手册查看二、命令行调试串口1. 查看设备节点2. 使用stty命令设置串口3. 查看串口配置信息4. 调试串口 三、代码编写1. 常用API2. 例程线程优化 前述 在开始实验前#xff0c;请一定要检查测试好所需硬件是否使用正常#xff0c;不然调试过程中出现的问题请一定要检查测试好所需硬件是否使用正常不然调试过程中出现的问题会让你很烦恼。因为我在测试的时候发现一直接收不到消息后面才知道ttl转usb的tx引脚坏了。所以确保硬件良好是我们后续测试的基本保障。
一、手册查看 我们前面讲到在Linux中一切皆是文件无论是上一章节的GPIO还是串口这边都同样如此。首先我们就先来使用命令行基本调试一下我们的串口来确保串口的可用性。无论是什么开发板我们都需要先查看手册来确定开发板的串口io。这里以香橙派AIPro为例手册中提醒我们串口0已经被系统使用不能当作普通串口给用户使用。 所以用户可用串口只有两个。分别是UART7和UART2。 查看设备节点如下所示。
二、命令行调试串口
1. 查看设备节点
设备节点都在 /dev目录下。
2. 使用stty命令设置串口
常用配置stty -F /dev/ttyAMA2 115200 cs8 -parenb -cstopb iutf8 3. 查看串口配置信息
命令stty -F /dev/ttyAMA2 -a
4. 调试串口
我们使用TTL转USB接口连接香橙派与电脑使用串口调试助手测试。注意在串口助手中要设置为UTF8显示。 坑在使用TTL连接时一定要接地线以保证电气基准电位不要只接TX和RX
1香橙派发送数据
2香橙派接收数据
三、代码编写 终端设备属性结构体我们在操作一些设备文件时常常会用到下面这个结构体。在Unix系统中常用于控制终端的输入输出参数比如波特率、字符大小、控制字符等。通过操作这个结构体可以对终端的各种属性进行设置和获取。 头文件#includetermios.h
struct termios {unsigned short c_iflag;//控制终端的输入方式如是否启用回车、换行等unsigned short c_oflag; //控制终端的输出方式如是否启用回车、换行等。unsigned short c_cflag; //控制终端的控制模式如波特率、数据位数等。unsigned short c_lflag;//控制终端的本地模式如是否启用回显、是否启用信号等。unsigned char c_line;//行线规程指定终端的行规程比如终端是终端设备还是伪终端设备。unsigned char c_cc[NCC]; //控制字符数组用于定义特殊控制字符的行为比如终端中的删除、结束、停止等功能键的行为。
};这些成员里都有很多配置参数的宏定义我们只需要将成员与要配置参数的宏定义进行|置1或~置0操作即可配置相应功能。我这里只先列举出来几个常用的功能。这里我将不再展示参数的宏定义因为太多了很多也用不到有需要的自己去查看其他博客来学习。
●配置举例如下
struct termios termios_p; //初始化结构体
termios_p.c_cflag |CS8; //设置八位数据位。
termios_p.c_cflag ~CSTOPB; //设置一位停止位。
termios_p.c_cflag ~PARENB; //无奇偶校验位。
termios_p.c_lflag ~ECHO ; //不回显1. 常用API
1设置波特率。 波特率常用 B2400B4800B9600B115200B460800。
int cfsetispeed(struct termios *termios_p,speed_t speed) //设置接收波特率
int cfsetospeed(struct termios *termios_p,speed_t speed) //设置发送波特率
//2清空缓冲区数据。 主要用于清除输入和输出缓冲区中的数据。这个命令在处理串口通信时非常有用特别是在初始化或重置通信通道时以确保没有残留的数据干扰通信。
int tcflush(int fd,int queue_selector)
//int fd 文件描述符
//int queue_selector
/* TCIFLUSH:清空正读的数据且不会读出TCOFLUSH:清空正写入的数据且不会发送到终端TCIOFLUSH:清空所有正在发生的 I/O 数据.*/3获取终端设备参数。 函数的作用是获取指定文件描述符fd所关联的终端设备的当前属性并将这些属性存储到指定的 termios 结构体termios_p中。
int tcgetattr(int fd,struct termios *termios_p)
//int fd 文件描述符。
//struct termios *termios_p 设备终端结构体。4设置终端设备参数激活配置。
int tcsetattr(int fd,int optional_actions,cons struct termios *termios_p)
//int fd 文件描述符。
//int optional_actions
/* TCSANOW:不等数据传输完毕立即改变属性TCSADRAIN:等所有数据传输完毕再改变属性TCSAFLUSH:清空输入输出缓冲区才改变属性
*/
//cons struct termios *termios_p 终端设备属性的结构体。2. 例程
uart.c
#include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include termios.h
#include unistd.h
#include string.h
#include uart.h
#include termios.hvoid UART_Close(int fd)
{close(fd);
}int UART_Send(int fd, char *data)
{int num;numwrite(fd, data, strlen(data));return num;
}int UART_Receive(int fd, char *receive)
{int num;numread(fd, receive, sizeof(receive)-1);return num;
}int UART_Init(char *device, int baud)
{int fd;int ret;struct termios termios_p;
//1.打开串口设备。不当作控制台。fd open(device, O_NOCTTY | O_RDWR);if (fd 0) {perror(open error);return -1;}
//2. 填充设备结构体memset(termios_p, 0 ,sizeof(termios_p));termios_p.c_cflag | CREAD; //使能接收器的接收功能必须配置的。termios_p.c_cflag | CLOCAL; //忽略调制解调器线路状态。termios_p.c_cflag |CS8; //设置八位数据位。//这里为了方便观看所以写出来下面的配置这里其实可以不写因为我们已经先前清空结构体了。termios_p.c_cflag ~CSTOPB; //设置一位停止位。termios_p.c_cflag ~PARENB; //无奇偶校验位。termios_p.c_lflag ~ECHO ; //不回显// 设置超时和最小读取字符数。必须配置termios_p.c_cc[VTIME] 1;termios_p.c_cc[VMIN] 128;switch (baud){ //设置波特率case 9600:cfsetispeed(termios_p,B9600); //设置接收波特率cfsetospeed(termios_p,B9600); //设置发送波特率break;case 115200:cfsetispeed(termios_p,B115200); //设置接收波特率cfsetospeed(termios_p,B115200); //设置发送波特率break;default:printf(不支持此波特率\n);break;}//3. 清空接收/发送缓冲准备发送和接收数据 tcflush(fd, TCIOFLUSH);//4. 将配置好的设备结构体设置上绑定激活设置的配置。ret tcsetattr( fd,TCSAFLUSH,termios_p);if (ret 0) {perror(tcsetattr error);return -3;}return fd; //返回文件描述符
}uart.h
#ifndef __UART_H
#define __UART_Hvoid UART_Close(int fd);
int UART_Init(char *device, int baud);
int UART_Receive(int fd, char *receive);
int UART_Send(int fd, char *data);
#endifmain.c
#include stdio.h
#include stdlib.h
#include uart.h
#include unistd.h
#include termios.h
#include string.h
int main()
{char buff[100];int fd;fdUART_Init(/dev/ttyAMA2,115200);if(fd0){perror(UART_Init error);return -1;}while(1){fgets(buff,sizeof(buff),stdin);UART_Send(fd, buff);}UART_Close(fd);return 0;
}线程优化
功能添加线程实现可收可发 main.c
#include stdio.h
#include stdlib.h
#include uart.h
#include unistd.h
#include termios.h
#include string.h
#include pthread.h
#include signal.hpthread_attr_t attr; //线程属性
int fd; //文件描述符void signal_task(int arg)
{printf(销毁相关属性\n);pthread_attr_destroy(attr); //销毁线程属性UART_Close(fd);exit(0);
}// 线程任务函数
void *task(void *arg) {int fd *(int *)arg;int ret;char buff[64];while (1) {memset(buff, 0, sizeof(buff));ret UART_Receive(fd, buff); // 读取数据到buff中if (ret 0) {buff[ret] \0; // 确保字符串以NULL结尾printf(Receive: %s\n, buff);} else break;}pthread_exit(NULL);
}int main()
{char buff[100];int ret;pthread_t thread;fdUART_Init(/dev/ttyAMA2,115200);if(fd0){perror(UART_Init error);return -1;}signal(2, signal_task);pthread_attr_init(attr); //初始化线程属性pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED); //设置子线程分离属性子线程推出后自动销毁。retpthread_create(thread,NULL,task,(void *)fd); //只有一个子线程可以取地址操作。if(ret0){perror(pthread_create error);return -1;}while(1){memset(buff,0,sizeof(buff));fgets(buff,sizeof(buff),stdin);UART_Send(fd, buff);}return 0;
}