当前位置: 首页 > news >正文

LubanCat-RK3568 UART串口通信,以及遇到bug笔记

  最近因项目需求,需要使用RK3568控制FPGA开发板来实现墨盒打印图片功能。项目的核心是通过UART通信协议将图像的像素点数据从RK3568主控芯片传输至FPGA开发板,再由FPGA控制墨盒打印图像。因此,本篇记录了项目中使用的主要技术、实现过程中的难点以及遇到的坑,旨在为后续的调试和优化提供参考。

1 rk3568开启串口

在这里插入图片描述
可以看到编号32、33为uart串口0,官网有两种打开方式,第一种方式不太好使,我直接采用第二种打开方式,通过修改设备树的配置文件进行修改:

cd  /boot/uEnv/
ls -al

在这里插入图片描述
可以看到uEnv.txt 软连接到uEnvLubanCat2-V3.txt,我们直接修改后者:
在这里插入图片描述
因为我们使用的uart3-m0,所以直接打开这个引脚:

sudo vim uEnvLubanCat2-V3.txt
# 修改完之后直接重启
sudo reboot

查看是否成功打开串口:

ls /dev/ttyS*

在这里插入图片描述
这里可以看到已经打开成功。

2 uart串口通信

2.1 uart串口通信代码

# UartUtil.hpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <termios.h>
#include <string.h>
#include <sys/ioctl.h>
#include <iostream>
#include <fstream>
using namespace std;
class UartUtil
{
public:UartUtil(){}~UartUtil(){close(m_nUartFd);}
public:bool InitUart(const char* fdUrl){m_nUartFd = open(fdUrl, O_RDWR);if (m_nUartFd < 0){printf("Fail to Open %s device\n", fdUrl);return 0;}//第三部分代码/struct termios opt;//清空串口接收缓冲区tcflush(m_nUartFd, TCIOFLUSH);// 获取串口参数opttcgetattr(m_nUartFd, &opt);// //设置串口输出波特率cfsetospeed(&opt, B9600);//设置串口输入波特率cfsetispeed(&opt, B9600);//B115200// cfsetospeed(&opt, B115200);// //设置串口输入波特率// cfsetispeed(&opt, B115200);//设置数据位数opt.c_cflag &= ~CSIZE;opt.c_cflag |= CS8;//opt.c_iflag |= IGNCR;// 设置OFILL标志,启用填充字符功能//opt.c_oflag |= OFILL;  //开启XON/XOFF流控制//opt.c_cflag |= IXON;//CS6//opt.c_cflag |= CS6;// //校验位// opt.c_cflag &= ~PARENB;// opt.c_iflag &= ~INPCK;//设置停止位,停止位为1opt.c_cflag &= ~CSTOPB;//更新配置tcsetattr(m_nUartFd, TCSANOW, &opt);return true;}bool WriteData1(unsigned char dataBuf){int bufSize = write(m_nUartFd, &dataBuf, sizeof(dataBuf));if(bufSize > 0){return true;}else{printf("Write Data Failed!!\n");return false;}return true;}private:int m_nUartFd;};

这里的fdUrl参数就是步骤1中的 /dev/ttyS3,可以在InitUart函数里面设置串口通信参数,具体我这代码怎么来的,是参考官网代码进行封装的,如果想要自己封装uart串口功能的,具体可以参考以下地址。
Lubancat Uart串口代码地址

2.2 uart代码参数

2.2.1 termios结构体

它是在头文件<termios.h>包含的<bits/termios.h>中定义的, 该文件中还包含了各个结构体成员可使用的宏值,具体定义如下:

struct termios {tcflag_t c_iflag; /* input mode flags */tcflag_t c_oflag; /* output mode flags */tcflag_t c_cflag; /* control mode flags */tcflag_t c_lflag; /* local mode flags */cc_t c_line; /* line discipline */cc_t c_cc[NCCS]; /* control characters */speed_t c_ispeed; /* input speed */speed_t c_ospeed; /* output speed */#define _HAVE_STRUCT_TERMIOS_C_ISPEED 1#define _HAVE_STRUCT_TERMIOS_C_OSPEED 1};

c_iflag:输入(input)模式标志,用于控制如何对串口输入的字符进行处理,常用的选项值见下表。
在这里插入图片描述

c_oflag:输出(output)模式标志,用于控制串口的输出模式,常用的选项值见下表。
在这里插入图片描述

c_cflag:控制(control)模式标志,用于控制串口的基本参数,如数据位、停止位等, 常用配置见下表,特别地,c_cflag结构体成员还包含了波特率的参数。
在这里插入图片描述

c_lflag:本地(local)模式标志,主要用于控制驱动程序与用户的交互,在串口通信中, 实际上用不到该成员变量。
在这里插入图片描述

3 RGBA转CMY代码

void PrintImage::RGBASerialImage(std::string picUrl, bool isSave) 
{cv::Mat image = cv::imread(picUrl, cv::IMREAD_UNCHANGED);if(image.empty()){std::cerr<<"RGBASerialImage Failed To Load Image!!"<<std::endl;return;}cv::resize(image, image, cv::Size(100, 100));delayImg = image;if (image.channels() == 4) {std::vector<cv::Mat> channels(4);  cv::split(image, channels);  cv::Mat rgbImg;std::vector<cv::Mat> arrChRGB;  arrChRGB.push_back(channels[0]);arrChRGB.push_back(channels[1]);arrChRGB.push_back(channels[2]);cv::merge(arrChRGB,rgbImg);cv::Mat resImg;rgbImg.copyTo(resImg, channels[3]);// 获取图像的尺寸int height = resImg.rows;int width = resImg.cols;// 遍历每个像素点for (int i = 0; i < height; ++i) {vector<uchar> arrCPixels;vector<uchar> arrMPixels;vector<uchar> arrYPixels;for (int j = 0; j < width; ++j) {// 获取当前像素的 BGR 值cv::Vec3b pixel = resImg.at<cv::Vec3b>(i, j);uchar blue = pixel[0];uchar green = pixel[1];uchar red = pixel[2];if(red == 0 && green == 0 && blue == 0){arrCPixels.push_back(0x00);arrMPixels.push_back(0x00);arrYPixels.push_back(0x00);continue;}/////////////R-->C//G-->M//B-->Yfloat perCPixel = (255.0f - (float)red) / 255.0f;float perMPixel = (255.0f - (float)green) / 255.0f;float perYPixel = (255.0f - (float)blue) / 255.0f;uchar cPixel = perCPixel * INKJET_DIV;uchar mPixel = perMPixel * INKJET_DIV;uchar yPixel = perYPixel * INKJET_DIV;if(cPixel == 10)cPixel++;if(mPixel == 10)mPixel++;if(yPixel == 10)yPixel++;arrCPixels.push_back(cPixel);arrMPixels.push_back(mPixel);arrYPixels.push_back(yPixel);}m_arrCPixels.push_back(arrCPixels);m_arrMPixels.push_back(arrMPixels);m_arrYPixels.push_back(arrYPixels);}} else {std::cout << "Please Input The Correct Path Of Picture!!" << std::endl;}
}

这里解释一下,为什么遇到10就自增像素点,就要说到我遇到的一个bug,通过串口通信发送像素点给FPGA开发板时,其他像素点都是一个Byte的16进制数,发送10时接收到两个16进制数。

3.1 传值bug请添加图片描述

可以看到只要是发送10,uart自动接收两个Bytes,下面是测试代码:

//uart_send.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <termios.h>
#include <string.h>
#include <sys/ioctl.h>const char default_path[] = "/dev/ttyS3";int main(int argc, char *argv[]) {int fd;unsigned char nData;// 如果有输入参数,就将其转换为 unsigned char 类型if (argc > 1) {nData = (unsigned char)atoi(argv[1]);  // 将字符串转换为整数} else {nData = 0xff;  // 默认值}fd = open(default_path, O_RDWR);if (fd < 0) {printf("无法打开 %s 设备\n", default_path);return 0;}struct termios opt;// 清空串口接收缓冲区tcflush(fd, TCIOFLUSH);// 获取串口参数tcgetattr(fd, &opt);// 设置串口输出和输入波特率cfsetospeed(&opt, B9600);cfsetispeed(&opt, B9600);// 设置数据位数opt.c_cflag &= ~CSIZE;opt.c_cflag |= CS8; // 无校验位opt.c_cflag &= ~PARENB;opt.c_iflag &= ~INPCK;// 设置停止位opt.c_cflag &= ~CSTOPB;// 更新配置tcsetattr(fd, TCSANOW, &opt);// 发送数据;写入时需要 nData 的地址和大小write(fd, &nData, sizeof(nData));close(fd);return 0;
}

总结

  这个项目的目标是通过RK3568主控芯片与FPGA开发板的配合,实现墨盒打印图像的功能。通过UART通信协议将图像的像素点数据传输给FPGA,再由FPGA控制墨盒完成打印。这一过程涉及多个技术环节,包括数据传输、图像处理和打印控制,后续有时间再去整理fpga代码方面的通用技能

http://www.xdnf.cn/news/1388503.html

相关文章:

  • 实时音视频延迟优化指南:从原理到实践
  • Less运算
  • (一)Python语法基础(上)
  • C++中float与double的区别和联系
  • 基于STM32设计的智能宠物喂养系统(华为云IOT)_273
  • 迅为RK3588开发板安卓串口RS485App开发-硬件连接
  • 智慧工地源码
  • 如何将iPhone日历传输到电脑
  • Webrtc支持FFMPEG硬解码之Intel
  • 【React】登录(一)
  • 2025 年 8 月《DeepSeek-V3.1 SQL 能力评测报告》发布
  • OpenCV 图像预处理核心技术:阈值处理与滤波去噪
  • 强化学习的“GPT-3 时刻”即将到来
  • 【C语言16天强化训练】从基础入门到进阶:Day 15
  • centos8部署miniconda、nodejs
  • 音频转音频
  • vue3新特性
  • 【Tools】C#文件自动生成UML图
  • Java流程控制03——顺序结构(本文为个人学习笔记,内容整理自哔哩哔哩UP主【遇见狂神说】的公开课程。 > 所有知识点归属原作者,仅作非商业用途分享)
  • “设计深圳”亚洲权威消费科技与室内设计盛会
  • Nginx高级配置 | Nginx变量使用
  • RoadMP3告别车载音乐烦恼,一键get兼容音频
  • 20250828在荣品RD-RK3588-MID开发板的Android13系统下适配Bainianxing的GPS模块BU-16M10
  • STM32项目分享:基于单片机的自行车测速系统设计
  • C++ DDS框架学习
  • 【前端教程】用 JavaScript 实现4个常用时间与颜色交互功能
  • mysql安全运维之常见攻击类型与防御指南-从SQL注入到权限提升
  • iOS 文件管理与 uni-app 性能优化实战 多工具协作的完整指南
  • 知识卡片html5动态网页源码
  • 2025-08-28-zabbix5.0创建监控项通过脚本简单实现监控oracle11g的磁盘组和表空间的使用量