实例介绍
【实例简介】
- 后台串口读取线程:在SerialOpen函数中,我们启动了一个后台线程serialReadThread,它不断地从串口读取数据并将数据写入环形缓冲区。
- 环形缓冲区:缓冲区使用互斥锁进行保护,确保在多线程环境下安全地读写数据。
- SerialReceive:外部线程可以通过调用SerialReceive函数来检查缓冲区是否包含完整的数据包,如果包含,就将数据包返回。
外部调用:
在外部线程中,你可以通过不断调用SerialReceive来获取串口数据包:
【实例截图】
【核心代码】
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <android/log.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <pthread.h>
#define BUFFER_SIZE 1024 // 环形缓冲区大小
#define PACKET_START 0xEF37
#define PACKET_END 0xFE73
#define TAG "SerialPort" // 日志标签
// 封装日志宏
#define LOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##__VA_ARGS__)
#define LOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##__VA_ARGS__)
#define LOGD(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##__VA_ARGS__)
// 环形缓冲区
unsigned char ringBuffer[BUFFER_SIZE];
int head = 0; // 缓冲区头指针
int tail = 0; // 缓冲区尾指针
pthread_mutex_t bufferMutex = PTHREAD_MUTEX_INITIALIZER; // 缓冲区互斥锁
// 串口文件描述符
int fd_ = -1;
pthread_t serialThread; // 串口读取线程
// 向环形缓冲区写入数据
int writeRingBuffer(const unsigned char* data, int size)
{
int bytesWritten = 0;
for (int i = 0; i < size; i ) {
ringBuffer[head] = data[i];
head = (head 1) % BUFFER_SIZE; // 环形缓冲区的循环
bytesWritten ;
}
return bytesWritten;
}
// 从环形缓冲区读取数据包
int readPacket(unsigned char* packetBuffer, int maxSize)
{
int packetStartIndex = -1;
int packetEndIndex = -1;
int packetSize = 0;
// 查找数据包的起始和结束位置
for (int i = tail; i != head; i = (i 1) % BUFFER_SIZE) {
// 检查是否找到包的起始字节
if (i 1 != head && (ringBuffer[i] << 8 | ringBuffer[(i 1) % BUFFER_SIZE]) == PACKET_START) {
packetStartIndex = i;
}
// 如果找到了包的起始字节,继续寻找结束字节
if (packetStartIndex != -1) {
if (i 1 != head && (ringBuffer[i] << 8 | ringBuffer[(i 1) % BUFFER_SIZE]) == PACKET_END) {
packetEndIndex = i;
break;
}
}
}
// 如果找到了完整的包
if (packetStartIndex != -1 && packetEndIndex != -1) {
packetSize = (packetEndIndex - packetStartIndex BUFFER_SIZE) % BUFFER_SIZE 2; // 2 for the start and end markers
// 拷贝数据包到 packetBuffer
int idx = 0;
for (int i = packetStartIndex; i != packetEndIndex; i = (i 1) % BUFFER_SIZE) {
packetBuffer[idx ] = ringBuffer[i];
}
packetBuffer[idx ] = ringBuffer[packetEndIndex]; // 末尾字节
packetBuffer[idx ] = ringBuffer[(packetEndIndex 1) % BUFFER_SIZE]; // 结束字节
// 更新缓冲区尾指针
tail = (packetEndIndex 2) % BUFFER_SIZE;
// 打印日志
LOGI("Found packet of size %d", packetSize);
return packetSize;
}
return 0; // 如果没有找到完整的数据包
}
// 串口接收数据模拟函数
int SerialReceive(unsigned char* buff, int len)
{
pthread_mutex_lock(&bufferMutex); // 锁住缓冲区
int packetSize = readPacket(buff, len);
pthread_mutex_unlock(&bufferMutex); // 解锁缓冲区
return packetSize;
}
// 串口读取线程
void* serialReadThread(void* arg)
{
unsigned char recvBuffer[256];
while (1) {
if (fd_ < 0) {
LOGE("Serial port is not open");
continue;
}
int readSize = read(fd_, recvBuffer, sizeof(recvBuffer));
if (readSize > 0) {
// 将读取的数据写入环形缓冲区
pthread_mutex_lock(&bufferMutex); // 锁住缓冲区
writeRingBuffer(recvBuffer, readSize);
pthread_mutex_unlock(&bufferMutex); // 解锁缓冲区
LOGI("Read %d bytes from serial port", readSize);
} else if (readSize < 0) {
LOGE("Error reading from serial port");
}
usleep(100000); // 稍微延时
}
return NULL;
}
extern "C" {
// 打开串口
bool SerialOpen(char* sPort, int speed)
{
if (fd_ > 0) // already open
return true;
// 打开串口
fd_ = open(sPort, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd_ == -1) {
LOGE("Failed to open serial port %s", sPort);
return false;
}
// 恢复串口为阻塞状态
if (fcntl(fd_, F_SETFL, 0) < 0) {
LOGE("Failed to set blocking mode");
return false;
}
// 设置串口配置
if (speed == 0) {
speed = 38400;
}
struct termios newtio;
bzero(&newtio, sizeof(newtio));
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
newtio.c_cflag |= CS8; // 8 data bits
// 设置波特率
cfsetispeed(&newtio, B38400);
cfsetospeed(&newtio, B38400);
// 设置停止位和奇偶校验
newtio.c_cflag &= ~CSTOPB;
newtio.c_cflag &= ~PARENB;
newtio.c_cc[VTIME] = 1;
newtio.c_cc[VMIN] = 1;
tcflush(fd_, TCIFLUSH);
if (tcsetattr(fd_, TCSANOW, &newtio) != 0) {
LOGE("Failed to configure serial port");
return false;
}
LOGI("Serial port opened successfully");
// 启动串口读取线程
if (pthread_create(&serialThread, NULL, serialReadThread, NULL) != 0) {
LOGE("Failed to create serial read thread");
return false;
}
return true;
}
// 关闭串口
void SerialClose()
{
if (fd_ > 0) {
close(fd_);
fd_ = -1;
pthread_cancel(serialThread); // 取消串口读取线程
LOGI("Serial port closed");
}
}
}
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论