Linux_UART代码

串口参数设置及查看

stty -F /dev/ttyS1 ispeed 4800 ospeed 4800 cs8
stty -F /dev/ttyS1 -a |head -n 1

读串口代码

#include <stdlib.h>
#include  <fcntl.h>
#include  "stdio.h"
#include  "termios.h"
#include  "unistd.h"
#include  "limits.h"
#include  <stdint.h>
#include  "time.h"
 //===================
#include <sys/select.h>
#include <sys/time.h>
 //===================
 
 
#define   UART_DEV   "/dev/ttyUSB0" //根据电脑插入的串口号定义
 
 
void main()
{
    int fd =0;
    int RxLen=0;
    uint8_t RxBuff[1024]={0};
 
    //==========串口打开============//
    fd = open(UART_DEV ,O_RDWR|O_NOCTTY);
    if(fd<0){
      printf("COM (%s) Open Fail ! \n",UART_DEV); //必须要权限.
      return;
    }
    
  
    printf("COM (%s) Open Success ! Watting recv...\n\n",UART_DEV);
    //==========配置串口============//
    struct  termios opt;          //配置串口的属性定义在结构体struct termios中
    tcgetattr(fd, & opt);         //获取终端控制属性
 
    cfsetispeed(& opt, B115200);  //指定输入波特率(若不设置系统默认9600bps)
    cfsetospeed(& opt, B115200);  //指定输出波特率(若不设置系统默认9600bps)
 
    /* c_lflag 本地模式 */
    opt.c_cflag &= ~ INPCK;           //不启用输入奇偶检测
    opt.c_cflag |= (CLOCAL |  CREAD); //CLOCAL忽略 modem 控制线,CREAD打开接受者
 
    /* c_lflag 本地模式 */
    opt.c_lflag &= ~(ICANON | ECHO | ECHOE |  ISIG); //ICANON启用标准模式;ECHO回显输入字符;ECHOE如果同时设置了 ICANON,字符 ERASE 擦除前一个输入字符,WERASE 擦除前一个词;ISIG当接受到字符 INTR, QUIT, SUSP, 或 DSUSP 时,产生相应的信号
 
    /* c_oflag 输出模式 */
    opt.c_oflag &= ~ OPOST;             //OPOST启用具体实现自行定义的输出处理
    opt.c_oflag &= ~(ONLCR | OCRNL);    //ONLCR将输出中的新行符映射为回车-换行,OCRNL将输出中的回车映射为新行符
 
    /* c_iflag 输入模式 */
    opt.c_iflag &= ~(ICRNL |  INLCR);          //ICRNL将输入中的回车翻译为新行 (除非设置了 IGNCR),INLCR将输入中的 NL 翻译为 CR
    opt.c_iflag &= ~(IXON | IXOFF | IXANY);    //IXON启用输出的 XON/XOFF流控制,IXOFF启用输入的 XON/XOFF流控制,IXANY(不属于 POSIX.1;XSI) 允许任何字符来重新开始输出
 
    /* c_cflag 控制模式 */
    opt.c_cflag &= ~ CSIZE;     //字符长度掩码,取值为 CS5, CS6, CS7, 或 CS8,加~就是无
    opt.c_cflag |=  CS8;        //数据宽度是8bit
    opt.c_cflag &= ~ CSTOPB;    //CSTOPB设置两个停止位,而不是一个,加~就是设置一个停止位
    opt.c_cflag &= ~ PARENB;    //PARENB允许输出产生奇偶信息以及输入的奇偶校验,加~就是无校验
 
    /* c_cc[NCCS] 控制字符 */
    opt.c_cc[VTIME] = 0 ;   //等待数据时间(10秒的倍数),每个单位是0.1秒  若20就是2秒
    opt.c_cc[VMIN] = 0 ;    //最少可读数据,非规范模式读取时的最小字符数,设为0则为非阻塞,如果设为其它值则阻塞,直到读到到对应的数据,就像一个阀值一样,比如设为8,如果只接收到3个数据,那么它是不会返回的,只有凑齐8个数据后一齐才READ返回,阻塞在那儿
    /* new_cfg.c_cc[VMIN]   =   8;//DATA_LEN;
       new_cfg.c_cc[VTIME]  =   20;//每个单位是0.1秒  20就是2秒
       如果这样设置,就完全阻塞了,只有串口收到至少8个数据才会对READ立即返回,或才少于8个数据时,超时2秒也会有返回
       另外特别注意的是当设置VTIME后,如果read第三个参数小于VMIN ,将会将VMIN 修改为read的第三个参数*/
 
    /*TCIFLUSH  刷清输入队列
      TCOFLUSH  刷清输出队列
      TCIOFLUSH 刷清输入、输出队列*/
    tcflush(fd, TCIOFLUSH);         //刷串口清缓存
    tcsetattr(fd, TCSANOW, &opt);   //设置终端控制属性,TCSANOW:不等数据传输完毕就立即改变属性
 
    while(1)
    {
        //==========串口接收(字符串)============//
         while( ((RxLen = read(fd, RxBuff,sizeof(RxBuff))) > 0)   )
         {
	       RxBuff[RxLen] = 0; 
    	   printf( "%s",RxBuff);
         
         }
 
    }
 
}

实测结果:
在这里插入图片描述
在这里插入图片描述

串口读写

/*************************************************************************
    > File Name: series.c
    > Author: kayshi
    > Mail: kayshi2019@qq.com
    > Created Time: Sat 12 Sep 2020 02:18:21 PM CST
 ************************************************************************/
#include <stdio.h>      /*标准输入输出定义*/
#include <stdlib.h>     /*标准函数库定义*/
#include <string.h>
#include <unistd.h>     /*Unix 标准函数定义*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>      /*文件控制定义*/
#include <termios.h>    /*PPSIX 终端控制定义*/
#include <errno.h>      /*错误号定义*/
#include <pthread.h>
#include <sys/timerfd.h>
#include <stdint.h>
#include <sys/time.h>

//#define bzero(a, b)       memset(a, 0, b)
#define PATH_TTY "/dev/ttyRS4"
uint8_t buf1[] = {0x68, 0x0F, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x49, 0x16};
uint8_t buf2[] = {0x68, 0x0F, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x12, 0x02, 0x00, 0x58, 0x16};
uint8_t buf3[] = {0x68, 0x0F, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x02, 0x00, 0x48, 0x16};
int fd; 
/*
 * 打印数组
 */
void show_buf(uint8_t *buf, int len)
{
    int i;

    for (i = 0; i < len ; i++)
    {   
        printf("%02x ", buf[i]);
    }   
    printf("\n");
}
/*
 * 设置定时器事件
 */
static int timerfd_set(int timer_fd, uint32_t timer_ms)
{
    struct itimerspec new_value;

    new_value.it_value.tv_sec = timer_ms / 1000; //秒
    new_value.it_value.tv_nsec = 1000000 * (timer_ms % 1000); //纳秒

    new_value.it_interval.tv_sec = 0;
    new_value.it_interval.tv_nsec = 0;

    if (timerfd_settime(timer_fd, 0, &new_value, NULL) == -1) //设置定时器
    {   
        printf("timerfd_settime is err\n");
        return -1;
    }
    return 0;
}
/*
 * 接收数据线程
 */
static void thread_recv(void)
{
    uint8_t buf[512];
    int nread = 0;
    int i =0;
    int buf_size = 512;
    int max_fd;
    int timerfd;
    int fd_list[2]; //用来记录使用了哪些文件描述符
    fd_set fds;
    int rx_len = 0;

    //FD_ZERO(&fds);
    //FD_SET(fd, &fds);
    if ((timerfd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0)//创建一个定时器字符
    {
        printf("%s:%d timerfd create is fail\n", __FILE__, __LINE__);
    }
//    else
//    {
//        FD_SET(timerfd, &fds);
//    }

    fd_list[0] = fd;
    fd_list[1] = timerfd;

	//找到所有文件描述符的最大值,并加 1 作为select的第一个参数。这样做是因为,select有一个监听范围为0 - 第一个参数值。例如:设置了5,就会监听0 - 4
    if (fd > timerfd)
        max_fd = fd + 1;
    else
        max_fd = timerfd + 1;

    while(1)
    {
        FD_ZERO(&fds);//清0
        FD_SET(fd, &fds);//添加文件字符到集合重
        FD_SET(timerfd, &fds);//添加文件字符到集合重
        select(max_fd, &fds, NULL, NULL, NULL);//监听集合重是否有可以读的描述符,没有阻塞在这
        for (i = 0; i < 2; i++)
        {
            if (FD_ISSET(fd_list[i], &fds) == 0)//对比是哪个字符可以读
                continue;
            if (fd_list[i] == fd)//fd可以读,代表串口有数据到来
            {
                nread = read(fd, &buf[rx_len], buf_size - nread);//进行读取
                if(nread > 0)
                {
                    timerfd_set(timerfd, 1000);//把定时器打开,设置为1000ms,这样1000ms后定时器描述符就可以读
                    rx_len += nread;//定时器未到时间内收到的数据累加

                    if(rx_len > 512)//如果收到长度大于规定值,也表示读完
                    {
                        printf("recv:");
                        show_buf(buf, rx_len);
                        rx_len = 0;//长度清0,表述所有数据读完
                    }
                }
                else
                {
                    printf("receive failed\n");
                }
            }
            else if (fd_list[i] == timerfd)//定时器描述符可以读
            {
                printf("recv:");
                timerfd_set(timerfd, 0);  //关闭定时器
                show_buf(buf, rx_len);
                rx_len = 0;
            }
        }
    }
}
int serial_send(int fd, uint8_t *buff, uint32_t len)
{
    int i = 0;
    uint32_t tx_len = 0;

    if ((buff == NULL) || (len == 0))
    {
        return -1;
    }

    for (; i < len; i += tx_len)
    {
        tx_len = write(fd, &buff[i], len - i);
        if (tx_len == 0)
        {
            break;
        }
    }
    return 0;
}

int main(void)
{
    struct termios newtio;
    pthread_t id1;

    fd = open(PATH_TTY, O_RDWR | O_NOCTTY);
    if (-1 == fd)
    {
        printf("can't open %s\n", PATH_TTY);
        return -1;
    }
    printf("open %s sucess!\n", PATH_TTY);

    if (fcntl(fd, F_SETFL, 0) < 0) //设置串口为阻塞状态
    {
        printf("%s fcntl failed!\n", PATH_TTY);
    }

    if (isatty(STDIN_FILENO) == 0) //测试是否为终端设备
    {
        printf("%s standard input is not a terminal device\n", PATH_TTY);
    }

    if (tcgetattr(fd, &newtio) != 0)
    {
        printf("uart_config: tcgetattr");
        return -1;
    }
    bzero(&newtio, sizeof(newtio));
    newtio.c_cflag |= CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;
    newtio.c_cflag |= CS8;
    newtio.c_cflag |= PARENB;
    newtio.c_cflag &= ~PARODD;
    newtio.c_iflag |= INPCK;
    cfsetispeed(&newtio, B9600);
    cfsetospeed(&newtio, B9600);
    newtio.c_cflag &= ~CSTOPB;
    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN] = 0;

    tcflush(fd, TCIFLUSH);
    if ((tcsetattr(fd, TCSANOW, &newtio)) != 0)
    {
        perror("uart_config: tcsetattr");
        return -1;
    }

    if (pthread_create(&id1, NULL, (void *)thread_recv, NULL) != 0)
    {
        printf("Failed to create 10ms thread");
    }

    while(1)
    {
        printf("send:");
        show_buf(buf1, sizeof(buf1));
        serial_send(fd, buf1, sizeof(buf1));
        sleep(2);

        printf("send:");
        show_buf(buf2, sizeof(buf2));
        serial_send(fd, buf2, sizeof(buf2));
        sleep(2);

        printf("send:");
        show_buf(buf3, sizeof(buf3));
        serial_send(fd, buf3, sizeof(buf3));
        sleep(2);
    }
    return 0;
}

编译命令:添加 -lpthread或者-pthread

gcc rxtx.c -o rxtx.out -lpthread

如果需要多次调用select函数监听文件描述符,每次调用前都必须初始化结构体fd_set fds, 包括FD_ZERO和FD_SET,这是因为select调用之后fds的值就改变了,和你想要监听的值就有差异了,需要通过重复的初始化操作来进行恢复。
上面代码之所以要在接收到数据后启动定时器,就是为了在定时器的事件到达之前,把这段时间读到的数据全部放到一个buf中去,这是为了避免,一笔数据被分成2到n份接收到。通过这种方式可以做到只要在定时器未到时收到的数据,都集中放到一个buf中去
在这里插入图片描述

带有输入参数的串口收发

链接: https://blog.csdn.net/weixin_41471318/article/details/116230465

Makefile参考

链接: https://blog.csdn.net/yanhuan136675/article/details/82766466?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-82766466-blog-126346671.pc_relevant_3mothn_strategy_and_data_recovery&spm=1001.2101.3001.4242.1&utm_relevant_index=3

参考资料

链接: https://blog.csdn.net/weixin_43693705/article/details/126177624

CRC校验及编译遇到的错误

 gcc client2.c -o a.out
client2.c:29:14: 错误:expected ‘=,,,;,asm’ or ‘__attribute__’ before ‘auchCRCHi’
  uchar  code auchCRCHi[] = {
              ^
client2.c:58:14: 错误:expected ‘=,,,;,asm’ or ‘__attribute__’ before ‘auchCRCLo’
   uchar code auchCRCLo[] = {
              ^
client2.c: 在函数‘crc16’中:
client2.c:95:25: 错误:‘auchCRCHi’未声明(在此函数内第一次使用)
   uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
                         ^
client2.c:95:25: 附注:每个未声明的标识符在其出现的函数内只报告一次
client2.c:96:14: 错误:‘auchCRCLo’未声明(在此函数内第一次使用)
   uchCRCLo = auchCRCLo[uIndex] ;

原因是定义问题,单片机里定义:
code的作用是告诉单片机,我定义的数据要放在ROM(程序存储区)里面,写入后就不能再更改。
在这里插入图片描述
去掉code就可以编译通过:
在这里插入图片描述
链接: 校验工具
在这里插入图片描述
测试数据:

01 10 00 01 00 02 04 00 0a 00 0b

数组:

char bbuf[] = {0x01,0x10,0x00,0x01,0x00,0x02,0x04,0x00,0x0a,0x00,0x0b};

在这里插入图片描述
这里必须强调:a、b的类型必须为unsigned否则会出现错误
在这里插入图片描述引用头文件:

#include "crc16.h"

crc16.h

#ifndef _CRCTABLE_H_
#define _CRCTABLE_H_
extern const unsigned char CRCHi[];
extern const unsigned char CRCLo[];
unsigned int crc16(unsigned char *puchMsg, unsigned int usDataLen);
#endif

crc16.c

#include <stdio.h>
#include "crc16.h"

 #define uchar unsigned char
 #define uint unsigned int

/* CRC 高位字节值表 */ 
// uchar  code auchCRCHi[] = {
uchar auchCRCHi[] = { 
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 
} ; 
/* CRC低位字节值表*/ 
//  uchar code auchCRCLo[] = {
uchar auchCRCLo[] = { 
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 
0x43, 0x83, 0x41, 0x81, 0x80, 0x40 
} ;

unsigned int crc16(unsigned char *puchMsg, unsigned int usDataLen) 
{ 
	unsigned int uchCRCHi = 0xFF ; /* 高CRC字节初始化 */ 
	unsigned int uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */ 
	unsigned int uIndex ; /* CRC循环中的索引 */ 
	while (usDataLen--) { /* 传输消息缓冲区 */ 
	 
		uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC */ 
		uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ; 
		uchCRCLo = auchCRCLo[uIndex] ; 
	} 
	return (uchCRCHi << 8 | uchCRCLo) ; 
}

串口代码非阻塞模式

serport1fd = open(argv[1],O_RDWR | O_NOCTTY | O_NDELAY);//不成为控制终端程序,不受其他程序输出输出影响

这种open方式打开,进行串口昔日以通信测试比较顺利。
上述两种模式会出现只发送不接收现象

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <error.h>
#include <termios.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
typedef struct termios termios_t;

typedef struct serial_data{

    char databuf[100];//发送/接受数据
    int serfd;//串口文件描述符

}ser_Data;

void *sersend(void *arg);
void *serrecv(void *arg);

int main(int argc,char *argv[])
{
    pthread_t pid1,pid2;
    pthread_attr_t *pthread_arr1,*pthread_arr2;
    pthread_arr1 = NULL;
    pthread_arr2 = NULL;
    int serport1fd;


    /*   进行串口参数设置  */
    termios_t *ter_s = malloc(sizeof(*ter_s));

    serport1fd = open(argv[1],O_RDWR | O_NOCTTY | O_NDELAY);//不成为控制终端程序,不受其他程序输出输出影响
    if(serport1fd < 0){
        printf("%s open faild\r\n",argv[1]);
        return -1;
    }

    bzero(ter_s,sizeof(*ter_s));

    ter_s->c_cflag |= CLOCAL | CREAD; //激活本地连接与接受使能

    ter_s->c_cflag &= ~CSIZE;//失能数据位屏蔽
    ter_s->c_cflag |= CS8;//8位数据位

    ter_s->c_cflag &= ~CSTOPB;//1位停止位

    ter_s->c_cflag &= ~PARENB;//无校验位

    ter_s->c_cc[VTIME] = 0;
    ter_s->c_cc[VMIN] = 0;

    /*1 VMIN> 0 && VTIME> 0
        VMIN为最少读取的字符数,当读取到一个字符后,会启动一个定时器,在定时器超时事前,如果已经读取到了VMIN个字符,则read返回VMIN个字符。如果在接收到VMIN个字符之前,定时器已经超时,则read返回已读取到的字符,注意这个定时器会在每次读取到一个字符后重新启用,即重新开始计时,而且是读取到第一个字节后才启用,也就是说超时的情况下,至少读取到一个字节数据。
        2 VMIN > 0 && VTIME== 0
        在只有读取到VMIN个字符时,read才返回,可能造成read被永久阻塞。
        3 VMIN == 0 && VTIME> 0
        和第一种情况稍有不同,在接收到一个字节时或者定时器超时时,read返回。如果是超时这种情况,read返回值是0。
        4 VMIN == 0 && VTIME== 0
        这种情况下read总是立即就返回,即不会被阻塞。----by 解释粘贴自博客园
    */
    cfsetispeed(ter_s,B115200);//设置输入波特率
    cfsetospeed(ter_s,B115200);//设置输出波特率

    tcflush(serport1fd,TCIFLUSH);//刷清未处理的输入和/或输出

    if(tcsetattr(serport1fd,TCSANOW,ter_s) != 0){
            printf("com set error!\r\n");
    }
    
    
    char buffer[] = {"hello my world!\r\n"};
    char recvbuf[100] = {};

    ser_Data snd_data;
    ser_Data rec_data;
    
    snd_data.serfd = serport1fd;
    rec_data.serfd = serport1fd;

    memcpy(snd_data.databuf,buffer,strlen(buffer));//拷贝发送数据
    
    pthread_create(&pid1,pthread_arr1,sersend,(void *)&snd_data);
    pthread_create(&pid2,pthread_arr2,serrecv,(void *)&rec_data);

   
    ssize_t sizec;
    while(1){

            usleep(100000);
    }
    
    pthread_join(pid1,NULL);
    pthread_join(pid2,NULL);
    free(ter_s);
    return 0;
}


void *sersend(void *arg)//串口发送线程函数
{
    ser_Data *snd = (ser_Data *)arg ;
    int ret;
    while(1){
       ret = write(snd->serfd,snd->databuf,strlen(snd->databuf));
       if(ret > 0){
            printf("send success, data is  %s\r\n",snd->databuf);
       }else{
           printf("send error!\r\n");
       }
       usleep(300000);
       /*
       if(发生中断)
       break;//退出
       */
    }
}

void *serrecv(void *arg)//串口发送线程函数
{
 ser_Data *rec= (ser_Data *)arg ;
    int ret;
    while(1){
       ret = read(rec->serfd,rec->databuf,1024);
       if(ret > 0){
            printf("recv success,recv size is %d,data is  %s\r\n",ret,rec->databuf);
       }else{
           /*
            什么也不做
           */
       }
       usleep(1000);
       /*
       if(发生中断)
       break;//退出
       */
    }
}

UART接收jpg(未测试)

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>

#define BUFFER_SIZE 1024

int main() {
    int serial_fd, file_fd;
    char buffer[BUFFER_SIZE];
    ssize_t bytes_read;
    FILE *jpg_file;

    // 打开串口
    serial_fd = open("/dev/ttyS0", O_RDWR);
    if (serial_fd < 0) {
        perror("Error opening serial port");
        return 1;
    }

    // 打开文件
    jpg_file = fopen("received.jpg", "wb");
    if (jpg_file == NULL) {
        perror("Error opening file");
        close(serial_fd);
        return 1;
    }

    // 配置串口
    struct termios options;
    tcgetattr(serial_fd, &options);
    cfsetispeed(&options, B115200); // 设置波特率为 115200
    cfsetospeed(&options, B115200);
    options.c_cflag |= CS8; // 设置数据位为 8 bits
    options.c_cflag &= ~PARENB; // 禁用奇偶校验
    options.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用软件流控制
    options.c_cflag &= ~CSTOPB; // 设置停止位为 1 bit
    tcsetattr(serial_fd, TCSANOW, &options);

    // 读取数据并写入文件
    while ((bytes_read = read(serial_fd, buffer, BUFFER_SIZE)) > 0) {
        fwrite(buffer, 1, bytes_read, jpg_file);
    }

    // 关闭文件和串口
    fclose(jpg_file);
    close(serial_fd);

    return 0;
}

这段代码中,我们首先打开了串口设备 /dev/ttyS0 ,你可以根据实际情况修改成你要使用的串口设备(如 /dev/ttyUSB0 等)。

然后,我们打开了一个用于保存接收到 JPG 文件的文件,这里使用了 fopen 函数,并指定以二进制写入模式 “wb” 打开文件。你可以根据需要更改文件名和打开模式。

接下来,我们对串口进行了配置,使用了 tcgetattr 和 tcsetattr 函数获取和设置串口的属性,例如波特率、数据位、停止位和奇偶校验等。这里设置的波特率为 115200,数据位为 8 bits,禁用了奇偶校验和软件流控制,停止位设置为 1 bit。你可以根据需要调整这些设置。

在读取数据并写入文件的循环中,我们使用 read 函数从串口读取数据,并使用 fwrite 函数将数据写入文件。

最后,我们关闭了文件和串口,释放资源。

请注意,在运行这段代码之前,你需要以 root 权限运行程序,或者对串口设备文件(/dev/ttyS0 或其他)进行适当的权限设置。

这是一个简单的示例,实际应用中可能需要更多的错误处理、超时设置等。确保充分理解代码并根据实际需求进行修改和扩展。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值