前言

  平常的工作使用中,总是免不了要和串口打交道,协议的收发也经常通过串口来实现,海思3559下的串口和标准的linux下串口大同小异,可以参考之前zynq的串口编程,也可以直接阅读本文

使能串口

  最直接的方式就是将设备树中对应uart的status修改为 status = “okay”。海思实际加载的串口驱动是PL011,menuconfig查看配置Device Drivers > Character devices > Serial drivers中的ARM AMBA PL011 serial port support 和 Support for console on AMBA serial port是否有选择上。重新编译内核烧入,在/dev 下可以查看是否有串口设备ttyAMA0~4。sdk2.0.3.1版本默认是有的

查看串口配置

  可以使用linux的stty命令查看串口的配置参数。比如:stty -F /dev/ttyAMA0 -a


  同样可以使用stty命令设置串口参数,比如:stty -F /dev/ttyAMA0 ispeed 115200 ospeed 115200 cs8

查看串口数据收发

  一般调试串口,我们可以将TX与RT接在一起,自己发数据给自己接收,看数据是否正常。也可以使用cat 查看串口数据或是echo发送数据。
  发送数据:

echo "test 1234567890" > /dev/ttyAMA0

  接收数据:

cat /dev/ttyAMA0

查看串口硬件分配:

  串口的硬件分配状态,比如IO和中断使用情况可以在/proc/tty/driver下的ttyAMA 种查看:

注意

  如果串口的配置和数据的收发命令都能够正常,但是串口的引脚没有电平变化,这个可能是串口的复用功能没有设置,需要设置一下GPIO复用为串口功能。复用功能可以在设备树dts中设置,也可以使用海思的himm命令直接设置:

himm 0x120f0100 0x01 #UART2_RXD
himm 0x120f0104 0x01 #UART2_TXD

   这些都是和标注的linux一致的,不一样的是海思的串口经常需要代码初始化后才能操作,或者使用海思自己的microcom

收发测试代码

操作库函数头文件

/************************************************************************************************
*****Describe: This program is writen to operate HI35xx serial devices.                     *****
*****Author: xin.han                                                                        *****
*****Date: 2022-09-17                                                                       *****
*************************************************************************************************/
#ifndef _UART_H_
#define _UART_H_#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<termios.h>
#include<errno.h>
#include<string.h>
#include <signal.h>
#include "platform.h"
#include "parser.h"
#include "queue.h"//宏定义
// #define HI_FALSE  -1
// #define HI_TRUE     0
#ifdef debugprintf#define debugpri(mesg, args...) fprintf(stderr, "[HI Serial print:%s:%d:] " mesg "\n", __FILE__, __LINE__, ##args)
#else#define debugpri(mesg, args...)/*
*描述  : 打开串口
*参数  : HiSerDevice串口设备名 串口设备举例: /dev/ttyAMA1 /dev/ttyAMA2
*返回值: 成功返回fd,失败返回-1
*注意  :无
*/
int HI_Serial_Open(char* HiSerDevice);
/*
*描述  : 关闭串口
*参数  : fd文件描述符
*返回值: 成功返回fd,失败返回-1
*注意  :无
*/
void HI_Serial_Close(int fd);
/*
*描述  : 串口参数设置
*参数  : fd: 文件描述符
*        speed: 波特率.115200,19200,9600...
*        flow_ctrl: 流控
*        databits: 数据位 取值为5,6,7,8
*        stopbits: 停止位 取值为1,2
*        parity: 奇偶校验位   取值为N,W,O,S
*返回值: 成功返回0,失败返回-1
*注意  :无
*/
int HI_Serial_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity) ;
/*
*描述  : 串口初始化,实际还是串口参数设置
*参数  : fd: 文件描述符
*        speed: 波特率.115200,19200,9600...
*        flow_ctrl: 流控
*        databits: 数据位 取值为5,6,7,8
*        stopbits: 停止位 取值为1,2
*        parity: 奇偶校验位   取值为N,W,O,S
*返回值: 成功返回0,失败返回-1
*注意  :无
*/
int HI_Serial_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity);
/*
*描述  : 串口发送
*参数  : fd:文件描述符
*        send_buf:发送buf
*        data_len:数据长度
*返回值: 成功返回数据长度,失败返回-1
*注意  :无
*/
int HI_Serial_Send(int fd, char *send_buf,int data_len) ;
/*
*描述  : 串口接受
*参数  : fd:文件描述符
*        send_buf:接收buf
*        data_len:数据长度
*返回值: 成功返回数据长度,失败返回-1
*注意  :无
*/
int HI_Serial_Recv(int fd, char *rcv_buf,int data_len) ;
/*
*描述  : 串口接受函数线程
*参数  : 无
*返回值: 无
*注意  :无
*/
HI_VOID *uart_recv_task(HI_VOID *arg);
/*
*描述  : 串口发送函数线程
*参数  : 无
*返回值: 无
*注意  :无
*/
HI_VOID *uart_send_task(HI_VOID *arg);#endif#endif

操作库函数

/************************************************************************************************
*****Describe: This program is writen to operate HI35xx serial devices.                     *****
*****Author: xin.han                                                                        *****
*****Date: 2022-09-17                                                                       *****
*************************************************************************************************/#include "uart.h"int HiSerfd;
void HI_Serial_Close(int fd);void Hi_sigsegv(int dummy)
{if(HiSerfd > 0)HI_Serial_Close(HiSerfd);fprintf(stderr, "Hi Serial Caught SIGSEGV, Abort!\n");fclose(stderr);abort();
}void Hi_sigterm(int dummy)
{if(HiSerfd > 0)HI_Serial_Close(HiSerfd);fprintf(stderr, "Hi Serial Caught SIGTERM, Abort!\n");fclose(stderr);exit(0);
}void Hi_init_signals(void)
{struct sigaction sa;sa.sa_flags = 0;sigemptyset(&sa.sa_mask);sigaddset(&sa.sa_mask, SIGSEGV);sigaddset(&sa.sa_mask, SIGTERM);sigaddset(&sa.sa_mask, SIGPIPE);sa.sa_handler = Hi_sigsegv;sigaction(SIGSEGV, &sa, NULL);sa.sa_handler = Hi_sigterm;sigaction(SIGTERM, &sa, NULL);sa.sa_handler = SIG_IGN;sigaction(SIGPIPE, &sa, NULL);
}void HI_Serial_Usage(void)
{printf("Usage:\n");printf("\tmyhicom [-d] <HiSerialDevice> [-s] get netdeviece info [-rw] read or wite select\n");printf("\tmyhicom [-h] for more usage\n");printf("\tmyhicom [-v] the verson of the sofware\n");printf("\tExample:\n\tmyhicom -d /dev/ttyAMA1 -s 115200 -w HiSerial:HelloWorld\n");
}int HI_Serial_Open(char* HiSerDevice)
{  int fd;fd = open( HiSerDevice, O_RDWR|O_NOCTTY);//  O_RDWR : 可读可写 //  O_NOCTTY :该参数不会使打开的文件成为该进程的控制终端。如果没有指定这个标志,那么任何一个 输入都将会影响用户的进程。//  O_NDELAY :这个程序不关心DCD信号线所处的状态,端口的另一端是否激活或者停止。如果用户不指定了这个标志,则进程将会一直处在睡眠状态,直到DCD信号线被激活。// fd = open(HiSerDevice, O_RDWR|O_NOCTTY|O_NDELAY);  if (-1 == fd)  {  perror("HiSerial Can't Open Serial HiSerDevice");  return(-1);  }  //恢复串口为阻塞状态                                 if(fcntl(fd, F_SETFL, 0) < 0)  {  debugpri("fcntl failed!\n");  return(-1);  }       else  {  debugpri("fcntl=%d\n",fcntl(fd, F_SETFL,0));  }  //测试是否为终端设备      if(0 == isatty(STDIN_FILENO))  {  debugpri("standard input is not a terminal device\n");  return(-1);  }  else  {  debugpri("isatty success!\n");  }                printf("fd->open=%d\n",fd);  return fd;
}  void HI_Serial_Close(int fd)
{  if(fd > 0)close(fd); return;
}  int HI_Serial_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)
{  int   i;  // int   status;  int   speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300};  int   name_arr[] = {115200,  19200,  9600,  4800,  2400,  1200,  300};  struct termios options;  if( tcgetattr( fd,&options)  !=  0)  {  perror("SetupSerial 1");      return(-1);   }  //set buater rate for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)  {  if  (speed == name_arr[i])  {               cfsetispeed(&options, speed_arr[i]);   cfsetospeed(&options, speed_arr[i]);    }  }       //set control model options.c_cflag |= CLOCAL;  //清bit位 关闭流控字符 0x11 0x13options.c_cflag |= CREAD;  //清bit位 关闭流控字符 0x11 0x13options.c_iflag &= ~(INLCR|ICRNL);//清bit位 关闭字符映射 0x0a 0x0doptions.c_iflag &= ~(IXON);//清bit位 关闭流控字符 0x11 0x13//set flow controlswitch(flow_ctrl)  {  case 0 ://none  options.c_cflag &= ~CRTSCTS;  break;     case 1 ://use hard ware options.c_cflag |= CRTSCTS;  break;  case 2 ://use sofwareoptions.c_cflag |= IXON | IXOFF | IXANY;  break;  }  //select data bit   options.c_cflag &= ~CSIZE;  switch (databits)  {    case 5    :  options.c_cflag |= CS5;  break;  case 6    :  options.c_cflag |= CS6;  break;  case 7    :      options.c_cflag |= CS7;  break;  case 8:      options.c_cflag |= CS8;  break;    default:     fprintf(stderr,"Unsupported data size\n");  return (-1);   }  //select parity bit switch (parity)  {    case 'n':  case 'N'://无奇偶校验位  options.c_cflag &= ~PARENB;   options.c_iflag &= ~INPCK;      break;   case 'o':    case 'O'://设置为奇校验    options.c_cflag |= (PARODD | PARENB);   options.c_iflag |= INPCK;               break;   case 'e':   case 'E'://设置为偶校验  options.c_cflag |= PARENB;         options.c_cflag &= ~PARODD;         options.c_iflag |= INPCK;        break;  case 's':  case 'S'://设置为空格    options.c_cflag &= ~PARENB;  options.c_cflag &= ~CSTOPB;  break;   default:    fprintf(stderr,"Unsupported parity\n");      return (-1);   }   // set stopbit  switch (stopbits)  {    case 1:     options.c_cflag &= ~CSTOPB; break;   case 2:     options.c_cflag |= CSTOPB; break;  default:     fprintf(stderr,"Unsupported stop bits\n");   return (-1);  }  //修改输出模式,原始数据输出    options.c_oflag &= ~OPOST;  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  //options.c_lflag &= ~(ISIG | ICANON);  //set wait time   主要影响read函数/* options.c_cc[VTIME] = X;   //设置从获取到1个字节后开始计时的超时时间options.c_cc[VMIN] = Y;   //设置要求等待的最小字节数在原始模式下对read()函数的影响:1、X=0,Y!=0。函数read()只有在读取了Y个字节的数据或者收到一个信号的时候才返回;2、X!=0,Y=0。即使没有数据可以读取,read()函数等待X时间量后返回;3、X!=0,Y!=0。第一个字节数据到时开始,最先满足收到Y个字节或达超时时间X任意一个条件,read()返回;4、X=0,Y=0。即使读取不到任何数据,函数read也会立即返回。 */options.c_cc[VTIME] = 1;    /* 读取一个字符等待1*(1/10)s */      options.c_cc[VMIN] = 32;    /* 读取字符的最少个数为xx,单位是字节 */  tcflush(fd,TCIFLUSH);  // //激活配置 (将修改后的termios数据设置到串口中)  if (tcsetattr(fd,TCSANOW,&options) != 0)    {  perror("com set error!\n");    return -1;   }  return 0;
}  int HI_Serial_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)
{  // int err;  //设置串口数据帧格式  if (HI_Serial_Set(fd,speed,flow_ctrl,databits,stopbits,parity) == -1)  {                                                           return -1;  }  else  {  return  0;  }
}  int HI_Serial_Send(int fd, char *send_buf,int data_len)
{  int len = 0;  len = write(fd,send_buf,data_len);  if (len == data_len )  {  debugpri("send data is %s\n",send_buf);return len;  }       else     {                   tcflush(fd,TCOFLUSH);  return -1;  }  } int HI_Serial_Recv(int fd, char *rcv_buf,int data_len)
{  int len,fs_sel;  fd_set fs_read;  struct timeval time;  FD_ZERO(&fs_read);  FD_SET(fd,&fs_read);  time.tv_sec = 30;  time.tv_usec = 0;  // len = read(fd,rcv_buf,data_len);  // select fdsetfs_sel = select(fd+1,&fs_read,NULL,NULL,&time);  if(fs_sel)  {  len = read(fd,rcv_buf,data_len);  debugpri("HiSeral Receive Data = %s len = %d fs_sel = %d\n",rcv_buf,len,fs_sel);  return len;  }  else  {  debugpri("Hiserial haven't data receive!");  return -1;  }
}
HI_VOID *uart_recv_task(HI_VOID *arg)
{int len;char HiSerialDev[32]="/dev/ttyAMA1";// char sendbuf[1024]={0};char recvbuf[1024]={0};int SerialSpeed = 115200;int HiSerfd;int i;// Hi_init_signals();// HI_Serial_Usage();       HiSerfd = HI_Serial_Open(HiSerialDev);HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1,'N');while(1){len = HI_Serial_Recv(HiSerfd, recvbuf,sizeof(recvbuf)); // printf("serial_recv length is %d\n",len); if(len > 0)  {  printf(" ttyAMA1:recv origin data \n");// recvbuf[len] = '\0';  for (i = 0;i < len ;i++){printf("%02x  ",recvbuf[i]);  }printf("\n");  // memset(recvbuf,0,sizeof(recvbuf));//break;  }  else  {  //     printf("Hiserial haven't data receive \n");  }  // sleep(2);                       }// debugpri("myHicom write %s\n",optarg);// HiSerfd = HI_Serial_Open(HiSerialDev);// printf("fd = %d device = %s speed = %d\n",HiSerfd,HiSerialDev,SerialSpeed);// HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1,'N');                    // sprintf(sendbuf,"%s\n",optarg);                    // HI_Serial_Send(HiSerfd, sendbuf, strlen(sendbuf)+1); // if(HiSerfd > 0)//     HI_Serial_Close(HiSerfd);                 // break;return 0;
}HI_VOID *uart_send_task(HI_VOID *arg)
{char HiSerialDev[32]="/dev/ttyAMA1";char sendbuf[1024]="HelloWorld1234567890";// char recvbuf[1024]={0};// char sendbuf[] = {0};int SerialSpeed = 115200;int HiSerfd;// Hi_init_signals();// HI_Serial_Usage();       HiSerfd = HI_Serial_Open(HiSerialDev);HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1,'N');while(1){HI_Serial_Send(HiSerfd, sendbuf, strlen(sendbuf)+1); sleep(1);          }// debugpri("myHicom write %s\n",optarg);// HiSerfd = HI_Serial_Open(HiSerialDev);// printf("fd = %d device = %s speed = %d\n",HiSerfd,HiSerialDev,SerialSpeed);// HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1,'N');                    // sprintf(sendbuf,"%s\n",optarg);                    // HI_Serial_Send(HiSerfd, sendbuf, strlen(sendbuf)+1); // if(HiSerfd > 0)//     HI_Serial_Close(HiSerfd);                 // break;return 0;
}

还是新建两个线程,一个收一个发

HI_VOID *uart_recv_task(HI_VOID *arg)
{int len;char HiSerialDev[32]="/dev/ttyAMA1";// char sendbuf[1024]={0};char recvbuf[1024]={0};int SerialSpeed = 115200;int HiSerfd;int i;HiSerfd = HI_Serial_Open(HiSerialDev);HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1,'N');while(1){len = HI_Serial_Recv(HiSerfd, recvbuf,sizeof(recvbuf)); // printf("serial_recv length is %d\n",len); if(len > 0)  {  printf(" ttyAMA1:recv origin data \n");// recvbuf[len] = '\0';  for (i = 0;i < len ;i++){printf("%02x  ",recvbuf[i]);  }printf("\n");  // memset(recvbuf,0,sizeof(recvbuf));//break;  }  else  {  //     printf("Hiserial haven't data receive \n");  }  }return 0;
}
HI_VOID *uart_send_task(HI_VOID *arg)
{char HiSerialDev[32]="/dev/ttyAMA1";char sendbuf[1024]="HelloWorld1234567890";// char recvbuf[1024]={0};// char sendbuf[] = {0};int SerialSpeed = 115200;int HiSerfd;HiSerfd = HI_Serial_Open(HiSerialDev);HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1,'N');while(1){HI_Serial_Send(HiSerfd, sendbuf, strlen(sendbuf)+1); sleep(1);           }  return 0;
}

  还是比较简单的

  其实也不是海思的坑,做驱动的时候不影响,做应用的时候会稍微恶心一点
  每次接收的时候,如果内容短还好,一旦大于8个字,就会分成几次接收,倒也不会丢,现在自己要写应用了,为了方便肯定不能这么用了呀,一番检查发现是options.c_cc[VMIN] 的原因,默认是1,单位是字节,表示最少收到的字节数,select收到就会返回了
  options.c_cc[VTIME] = X;   //设置从获取到1个字节后开始计时的超时时间
  options.c_cc[VMIN] = Y;   //设置要求等待的最小字节数
  在原始模式下对read()函数的影响:
  1、X=0,Y!=0。函数read()只有在读取了Y个字节的数据或者收到一个信号的时候才返回;
  2、X!=0,Y=0。即使没有数据可以读取,read()函数等待X时间量后返回;
  3、X!=0,Y!=0。第一个字节数据到时开始,最先满足收到Y个字节或达超时时间X任意一个条件,read()返回;
  4、X=0,Y=0。即使读取不到任何数据,函数read也会立即返回。

海思3559万能平台搭建:串口编程相关推荐

  1. 海思3559万能平台搭建:DDR移植的一些问题

    前言:   开发板是绝对无误的硬件环境,但是我们平时的开发肯定会接触自己搭建的硬件环境,难免会有这样那样的小问题,这里给出一次DDR的调试过程 问题描述   海思3559开发板可以用默认配置表格生成的 ...

  2. 海思3559万能平台搭建:OSD实时叠加的支持1SDL库 FREETYPE库 SDL_TTF库的移植

    前言   万能平台字符叠加的功能自然少不了,但海思默认支持的都是静态位图,如果实时刷新或者我们向在屏幕上显示一些中文信息就捉襟见肘了,所以这里需要参考移植开源项目SDL的库来帮我们实现这一想法   网 ...

  3. 海思3559万能平台搭建:获取数据帧修改后编码

    前言   有了这么长的铺垫和反复的啃sample,现在开始搭建自己的平台就底气多了,倒也不至于万能平台哈哈,只是在完成配置文件的功能后,可以不用改代码重新编译,就可以实现多场景多平台多功能下的使用了 ...

  4. 海思3559万能平台搭建:在截获的YUV图像上画框

    前言   万里长征第二步,YUV的认识和编码还在进行中,熟悉了YUV格式的原理和储存方式后,我们就可以结合第一步中从vpss通道截获的YUV图像上尝试修改,叠加自己的算法,先简单粗暴的改改,后续在替换 ...

  5. 海思3559万能平台搭建:添加一个新的sensor

    前言   海思对摄像头的支持是只有固定的,如果我们想更换新的相机,让fpga接入通过lvds接口给3559提供视频源的话,除了相关配置,还需要添加新的sensor库,编译新的isp库,而且,如果移植不 ...

  6. 海思3559万能平台搭建:OSD功能的优化

    前言:   功能测试的OSD使用还是比较简单的,随便找个位置做个时间戳,背景还是黑色,且只能显示一行,很明显效果并不是那么理想,这里做一个升级,对海思区域叠加的配置以及osd窗口的创建等都在本文一并写 ...

  7. 海思3559万能平台搭建:OSD的自动反色

    前言   OSD功能在之前两篇中已经满足了大部分的应用场景,为了进一步提升效率和自适应环境亮度和反色,这里介绍改进方法 效率提升   我们之前整体的流程框架是这样的:TTF初始化,打开字体,区域初始化 ...

  8. 海思3559万能平台:VGS的画线处理

    前言   海思的OSD功能除了之前提到的第三方库,自己的VGS也可以做到一些简单的诸如画线之类的操作,这里介绍下假如类似识别时需要画矩形框的时候可以的一种做法 海思VGS简介   海思的VGS 是视频 ...

  9. 海思3559开发常识储备:相关名词全解

    前言   接连啃了两个sample,还是觉得笼笼统统模模糊糊,没有达到想要的一目了然的程度,那就再整理整理资料,补些硬货吧 图像和像素格式 颜色: (1)颜色是主观还是客观存在?    颜色的本质是光 ...

最新文章

  1. linux 文件查找与文件中注释去除
  2. linux中rm删除的文件是否可以恢复,Linux下用rm删除的文件的恢复方法
  3. Graph Embedding学习笔记(3):Graph Convolution Networks
  4. jquery 绑定动态元素
  5. tableau实战系列(三十五)-教你画个不一样的圆角条形图
  6. Android日期对话框NumberPicker的用法教程
  7. 数列分块入门 5(LibreOj-6281)
  8. 都是宝宝:北京孩子3成不玩电子游戏睡眠状况最好 江苏孩子起得最早
  9. c++内存优化:二级间接索引模式内存池
  10. python生成10个随机数字符串_python生成随机数、随机字符串
  11. ppp协议 服务器,详解PPP及PPPoE协议
  12. c语言图像的简单叠加,第10章C语言图形编程.ppt
  13. PFC颗粒6.0软件模拟---工程案例
  14. 关于VGA接口连接1080p显示器模糊多半是线的问题
  15. 【微信支付】微信支付之 Native 支付
  16. Java第一天笔记01——jdk8的安装与环境变量的配置
  17. 微信SDK删除支付模块流程
  18. 电信aep平台是什么意思_亚马逊电商平台是什么意思?亚马逊注册技巧
  19. Xmind2021安装激活破解
  20. ReactOS研究班

热门文章

  1. docker搭建samba服务smb网络磁盘共享
  2. Ansible - 使用CallBack + 如何自定义Callback
  3. 干货丨吴朝晖:混合智能概念与新进展
  4. 金蝶eas客户端更新报错404
  5. 华泰实施国强-Symix ERP软件(zt)
  6. 上传excel文件,导出excel模板实现
  7. 2021年美容师(高级)考试题库及美容师(高级)复审模拟考试
  8. 双系统的ubuntu18.04 安装QQ(wine)
  9. AltiumDesigner10设计不规则PCB形状
  10. js replace全部替换的方法