89、JPEG格式图像数据解析+串口传输JPEG解析

JPEG格式传输以(段标记SOI)0xFF 0xD8开始,(段标记EOI)0xFF 0xD9结束
解析JPEG格式数据驱动文件:
jpeg_driver.h

#ifndef _jpeg_driver_H_
#define _jpeg_driver_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"

typedef enum
{
    eJPEG_Segment_Error = -1,//错误值,标记用,不是类型码
    eJPEG_Segment_SOI = 0xD8,//文件头
    eJPEG_Segment_EOI = 0xD9,//文件尾
    eJPEG_Segment_SOF0 = 0xC0,//帧开始(标准JPEG)
    eJPEG_Segment_SOF1 = 0xC1,//同上
    eJPEG_Segment_DHT = 0xC4,//定义Huffman表
    eJPEG_Segment_SOS = 0xDA,//扫描行开始
    eJPEG_Segment_DQT = 0xDB,//定义量化表
    eJPEG_Segment_DRI = 0xDD,//定义重新开始间隔
    eJPEG_Segment_APP0 = 0xE0,//定义开始交换格式和图像识别信息
    eJPEG_Segment_COM = 0xFE,//注释
    eJPEG_Segment_DNL = 0xDC//定义扫描行数
}JPEG_SegmentCode_EnumDef;//JPEG数据段类型码值

extern JPEG_SegmentCode_EnumDef jpeg_SegmentDetection_driver(uint8_t format,uint8_t code);
extern int jpeg_SegmentAnalysis_driver(uint8_t *data,long int len);
extern int jpeg_FileSave(char *name,uint8_t *data,long int len);
extern uint8_t *jpeg_FileRead(char *name,long int *len);
extern int jpeg_ImageExtraction(uint8_t *data,long int len);

#ifdef __cplusplus
}
#endif
#endif


jpeg_driver.c

/**********************************************************************
*file:JPEG格式数据解析
*author:残梦
*versions:V1.0
*date:2024.05.23
*note:参考文档 jpeg图片格式详解:https://blog.csdn.net/yun_hen/article/details/78135122
**********************************************************************/
#include "jpeg_driver.h"
#include "stdio.h"
#include "stdlib.h"

#define dMerge_u16(MSB,LSB) ((((uint16_t)MSB)<<8) | ((uint16_t)LSB))//合并两个字节为uint16_t类型


/****************************************************
@function:jpeg格式检查
@param:format--JPEG段格式码;code--JPEG段类型码
@return:参看JPEG_SegmentCode_EnumDef
@note:
****************************************************/
JPEG_SegmentCode_EnumDef jpeg_SegmentDetection_driver(uint8_t format,uint8_t code)
{
    if(format != 0xFF)return eJPEG_Segment_Error;
    switch(code)
    {
        case eJPEG_Segment_SOI:
        case eJPEG_Segment_EOI:
        case eJPEG_Segment_SOF0:
        case eJPEG_Segment_SOF1:
        case eJPEG_Segment_DHT:
        case eJPEG_Segment_SOS:
        case eJPEG_Segment_DQT:
        case eJPEG_Segment_DRI:
        case eJPEG_Segment_APP0:
        case eJPEG_Segment_COM:
        case eJPEG_Segment_DNL:return (JPEG_SegmentCode_EnumDef)code;
        default:return eJPEG_Segment_Error;
    }
}

/****************************************************
@function:jpeg段格式信息解析
@param:data--数据区域,len--数据长度
@return:
    0--识别成功
    -1--段格式错误
    -2--段类型未识别
    -3--数据长度不足
    -4--数据解析出错误值
@note:
****************************************************/
int jpeg_SegmentAnalysis_driver(uint8_t *data,long int len)
{
    long int pos = 0,segment_len = 0,i = 0;
    uint8_t temp = 0;

    if(len < 2)return -3;
    if(data[pos++] != 0xFF)return -1;
    switch(data[pos++])
    {
        case eJPEG_Segment_SOI:
        {
            printf("\n\n/******************SOI*****************图片起始点/\n");
        }break;
        case eJPEG_Segment_EOI:
        {
            printf("\n\n/******************EOI*****************图片起始点/\n");
        }break;
        case eJPEG_Segment_SOF0:
        {
            len -= 2;
            if(len < 2)return -3;
            segment_len = dMerge_u16(data[pos],data[pos+1]);
            len -= 2;pos += 2;
            printf("eSOF0[%d]\n",segment_len);
            if(len < segment_len)return -3;

            printf("样本精度:%d\n",data[pos++]);
            printf("图片尺寸[宽度*高度]:[%d*%d]\n",dMerge_u16(data[pos],data[pos+1]),dMerge_u16(data[pos+2],data[pos+3]));pos += 4;
            temp = data[pos++];
            printf("组件数量:%d (1=灰度图,3=YCbCr/YIQ 彩色图,4=CMYK 彩色图)\n",temp);
            for(i = 0;i < temp;i++)
            {
                printf("组件ID:%d (1=Y, 2=Cb, 3=Cr, 4=I, 5=Q)\n",data[pos++]);
                printf("采样系数[垂直,水平]:[%d,%d]\n",(data[pos]&0x0F),(data[pos]>>4));pos++;
                printf("量化表号:%d\n",data[pos++]);
            }
        }break;
        case eJPEG_Segment_SOF1:
        {
            printf("SOF1\n");
        }break;
        case eJPEG_Segment_DHT:
        {
            len -= 2;
            if(len < 2)return -3;
            segment_len = dMerge_u16(data[pos],data[pos+1]);
            len -= 2;pos += 2;
            printf("DHT[%d]\n",segment_len);
            if(len < segment_len)return -3;

            printf("HT[%d号]信息:%d (HT类型, 0=DC表,1=AC表)\n",data[pos]&0x0F,data[pos]>>4);pos++;
        }break;
        case eJPEG_Segment_SOS:
        {
            len -= 2;
            if(len < 2)return -3;
            segment_len = dMerge_u16(data[pos],data[pos+1]);
            len -= 2;pos += 2;
            printf("SOS[%d]\n",segment_len);
            if(len < segment_len)return -3;

            temp = data[pos++];
            if((temp < 1) || (temp > 4))return -4;
            printf("扫描行内组件数量:%d\n",temp);

            for(i = 0;i < temp;i++)
            {
                printf("组件ID:%d\n",data[pos++]);
                printf("Huffman表号:AC=%d,DC=%d\n",data[pos]&0x0F,data[pos]>>4);pos++;
            }
        }break;
        case eJPEG_Segment_DQT:
        {
            len -= 2;
            if(len < 2)return -3;
            segment_len = dMerge_u16(data[pos],data[pos+1]);
            len -= 2;pos += 2;
            printf("DQT[%d]\n",segment_len);
            if(len < segment_len)return -3;

            printf("QT号:%d,精度:%d\n",(data[pos]&0x0F),((((data[pos]&0xF0)>>4) == 0)?8:0));pos++;//0-3位是QT号,4-7位QT精度,此处是0,所以精度是8bit,即1个字节
            printf("QT量化表:");
            for(;pos < (segment_len-3);pos++)printf("%02X ",data[pos]);
            printf("\n");
        }break;
        case eJPEG_Segment_DRI:
        {
            printf("DRI\n");
        }break;
        case eJPEG_Segment_APP0:
        {
            len -= 2;
            if(len < 2)return -3;
            segment_len = dMerge_u16(data[pos],data[pos+1]);
            len -= 2;pos += 2;
            printf("APP0[%d]\n",segment_len);
            if(len < segment_len)return -3;

            if((data[pos+0] == 0x4A) \
                && (data[pos+1] == 0x46)\
                && (data[pos+2] == 0x49)\
                && (data[pos+3] == 0x46)\
                && (data[pos+4] == 0x00))
            {
                printf("交换格式:JFIF\n");
            }
            else
            {
                printf("交换格式:未识别\n");
                return -1;
            }
            pos += 5;

            printf("版本:%d.%d\n",data[pos],data[pos+1]);pos += 2;
            printf("密度单位:%d\n",data[pos++]);
            printf("像素密度:[X,Y]:[%d,%d]\n",dMerge_u16(data[pos],data[pos+1]),dMerge_u16(data[pos+2],data[pos+3]));pos += 4;
            printf("缩略图密度:[X,Y]:[%d,%d]\n",data[pos],data[pos+1]);pos += 2;
        }break;
        case eJPEG_Segment_COM:
        {
            printf("COM\n");
        }break;
        case eJPEG_Segment_DNL:
        {
            printf("DNL\n");
        }break;
        default:return -2;
    }
    return 0;
}

/****************************************************
@function:将数据保存至文件
@param:
    name:文件名,需含文件后缀
    data--数据区域
    len--数据长度
@return:
    0--成功
    -1-参数异常
    -2--文件创建失败
@note:
****************************************************/
int jpeg_FileSave(char *name,uint8_t *data,long int len)
{
    FILE *file = NULL;
    if((name == NULL) || (data == NULL) || (len == 0))return -1;
    if((file = fopen(name, "wb")) == NULL)return -2;
    fwrite(data,1,len,file);
    fclose(file);
    return 0;
}

/****************************************************
@function:读取文件所有数据
@param:
    name:文件名,需含文件后缀
    len--数据长度
@return:
    数据地址,使用完毕后需要使用free释放该内存
    NULL--失败
@note:
****************************************************/
uint8_t *jpeg_FileRead(char *name,long int *len)
{
    FILE *file = NULL;
    uint8_t *data = NULL;

    if((name == NULL) || (len == NULL))return NULL;
    if((file = fopen(name, "rb")) == NULL)return NULL;
    fseek(file, 0, SEEK_END);
    *len = ftell(file);
    fseek(file, 0, 0);
    data = (unsigned char*)malloc(*len);
    fread(data, 1, *len, file);
    fclose(file);
    return data;
}

/****************************************************
@function:提取数据流中JPEG格式数据,并按顺序生成对应图像1.jpg,2.jpg,.....
@param:data--数据区域
@return:图像数量
@note:
****************************************************/
int jpeg_ImageExtraction(uint8_t *data,long int len)
{
    long int i = 0,pos = 0,num = 0;
    uint8_t flag = 0;
    char buf[20] = {0};

    //查找JPEG标识符
    for(i = 0;i < (len-1);i++)
    {
        if(jpeg_SegmentDetection_driver(data[i],data[i+1]) == eJPEG_Segment_Error)continue;
        if(data[i+1] == eJPEG_Segment_SOI)
        {
            pos = i;
            flag = 1;
        }
        else if(data[i+1] == eJPEG_Segment_EOI)
        {
            if(flag == 1)
            {
                sprintf(buf,"%d.jpg",num++);
                jpeg_FileSave(buf,&data[pos],(i+1 - pos + 1));
            }
            flag = 0;
        }
    }
    return num;
}


串口透传JPEG格式图像数据实例工程:

串口驱动文件:
uart_driver.c

/*********************************************
*file:labwindows CVI 串口UART驱动代码
*date:2023.06.25
*revision:V1.0
*author:残梦
*note:
eg:参见PanelUart0_UI.c文件,此文件做的是一个串口助手工具
*********************************************/
#include <windows.h>
#include <winreg.h>
#include <userint.h>
#include <utility.h>
#include "rs232.h"
#include "string.h"
#include "stdio.h"
#include "uart_driver.h"

#define MAX_BUF_NUM (1024)//串口收发缓冲大小

static int uart_GetComNum_driver(char strSerialList[256][25], int *comNum);

/****************************************
@function:打开串口
@param:uart--串口结构体
@return:负值--失败,0--正常
@note:
1、首次使用需清零uart的值
****************************************/
int uart_open_driver(uart_driver_StructDef *uart)
{
	char ComLab[10] = {0};

    //1、获取串口状态
    if(uart_StatusGet_driver(uart) == 0)return -1;

    //2、参数检查
    if(uart->configuration.port < 0){return -2;}
    if(uart->configuration.BaudRate < 0){return -2;}
    if(uart->configuration.parity < 0){return -2;}
    if(uart->configuration.dataBits < 0){return -2;}
    if(uart->configuration.stopBits < 0){return -2;}

    //3、建立串口
    memset(ComLab, 0, sizeof(ComLab));
    sprintf(ComLab,"COM%d",uart->configuration.port);
    if (OpenComConfig(uart->configuration.port, ComLab, (long)(uart->configuration.BaudRate),\
        (int)(uart->configuration.parity), (int)(uart->configuration.dataBits), (int)(uart->configuration.stopBits),\
        MAX_BUF_NUM,MAX_BUF_NUM) < 0)goto ERROR_PROCESS;
    InstallComCallback (uart->configuration.port, LWRS_RXCHAR,0, 0, uart->configuration.Callback, NULL);//LWRS_RXCHAR;//LWRS_TXEMPTY LWRS_RXFLAG | LWRS_RECEIVE
    SetCTSMode(uart->configuration.port,LWRS_HWHANDSHAKE_OFF); /* 禁止硬件握手,即不用RTS/CTS和DTR/DSR */
    FlushInQ(uart->configuration.port);   //清空输入队列的缓存数据
    FlushOutQ(uart->configuration.port);  //清空输出队列的缓存数据

    uart->private.status = 1;
    return 0;
ERROR_PROCESS:
    {
        uart->private.status = 0;
        return -3;
    }
}

/****************************************
@function:关闭串口
@param:uart--串口结构体
@return:void
@note:
****************************************/
void uart_close_driver(uart_driver_StructDef *uart)
{
    if(uart->private.status){CloseCom(uart->configuration.port);}
    uart->private.status = 0;
}

/****************************************
@function:获取串口状态
@param: 
        Bits:见uart_StatusBit_EnumDef
@return:-1=串口无效,0=串口正在使用
@note:
****************************************/
int uart_StatusGet_driver(uart_driver_StructDef *uart)
{
    int state = 0;

    if(uart->private.status)
    {
        state = GetComStat(uart->configuration.port);
        if((state < 0) || (state & 0x1080))
        {
            uart_close_driver(uart);
            uart->configuration.Abnormal_Callback();
            return -1;
        }
        return 0;
    }
    return -1;
}

/****************************************
@function:扫描可用串口,并添加到对应的面板Ring控件中
@param:panelHandle--面板句柄
        portID--Ring控件类型的ID值
@return:void
@note:显示样式:COM0、COM1....
****************************************/
void uart_ScanPort_driver(int panelHandle,int portID)
{
    char strSerialList[256][25]; int comNum,i = 0,com = 0;	

    ClearListCtrl(panelHandle,portID);
    if(uart_GetComNum_driver(strSerialList,&comNum) < 0){return;}
    for(i = 0;i < comNum;i++)
    {
        sscanf(strSerialList[i],"COM%d",&com);
        InsertListItem(panelHandle,portID, 0, strSerialList[i], com);
    }
}

/****************************************
@function:通过访问注册表获得串口号
@param:strSerialList--二维数组用来存放返回数组;
@return:-1--失败;0--成功
@note:
****************************************/
static int uart_GetComNum_driver(char strSerialList[256][25], int *comNum)
{
	char Name[25];
	int i = 0;
	unsigned char szPortName[25];
	long Status = 0.0;
	int dwIndex = 0;
	int dwName;
	int dwSizeofPortName;
	int Type;
	HKEY hKey; 						 								//返回注册表项的句柄
	if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM\\", 0, KEY_READ, &hKey) != ERROR_SUCCESS) //打开注册表
		return -1;
	dwName = sizeof(Name);
	dwSizeofPortName = sizeof(szPortName);
	while((Status == ERROR_SUCCESS)||(Status == ERROR_MORE_DATA))
	{
		Status = RegEnumValue(hKey, dwIndex++, Name, &dwName, NULL, &Type, szPortName, &dwSizeofPortName); //列举注册表的值
		if((Status == ERROR_SUCCESS)||(Status == ERROR_MORE_DATA))
		{
			strcpy(strSerialList[i], (const char*)szPortName);       // 串口字符串保存
			//printf("%s %d\n",strSerialList[i],i);
			i++;
		}
		dwName = sizeof(Name); 
		dwSizeofPortName = sizeof(szPortName); 
	}
	*comNum = i;
	RegCloseKey(hKey);												//关闭注册表
	return 0;	
}

/****************************************
@function:接收串口数据
@param: portNumber--端口号
        data--数据接收区
        BytesNumber--接收数据最大字节数,最大1025字节,退出函数时此值表示实际接收字节数
@return:-1--失败,0--成功
@note:data建议1025字节
****************************************/
int uart_DataReceive_driver(int portNumber,char *data,size_t *BytesNumber)
{
    size_t number = 0;

    if(data == NULL)return -1;
    number = GetInQLen(portNumber);
    *BytesNumber = (number > *BytesNumber)?*BytesNumber:number;
    *BytesNumber = (*BytesNumber > MAX_BUF_NUM)?MAX_BUF_NUM:*BytesNumber;

    if(ComRd(portNumber,data,*BytesNumber) < 0)return -1;//接收,GetInQLen用于得到Com口的输入队列数据缓存的大小
    data[*BytesNumber] = '\0';
    return 0;
}

/****************************************
@function:中断函数中接收串口数据
@param: portNumber--端口号
        eventMask--中断事件码
        data--数据接收区,需大于BytesNumber一个字节
        BytesNumber--接收数据最大字节数,最大1025字节,退出函数时此值表示实际接收字节数
@return:-1--失败,0--成功
@note:data建议1025字节
****************************************/
int uart_DataReceive_IT_driver(int portNumber,int eventMask,char *data,size_t *BytesNumber)
{
    if (eventMask & LWRS_RXCHAR)
    {
        return uart_DataReceive_driver(portNumber,data,BytesNumber);
    }
    return -1;
}

/****************************************
@function:串口发送数据,按ASCII值发送
@param: uart--串口结构体
        data--数据区
        BytesNumber--字节数
@return:-1--失败,0--成功
@note:
****************************************/
int uart_DataTransmit_driver(uart_driver_StructDef *uart,char data[],size_t BytesNumber)
{
    if(uart_StatusGet_driver(uart) < 0)return -1;
    if(BytesNumber != ComWrt (uart->configuration.port, data, BytesNumber))return -1;
    return 0;
}

/****************************************
@function:ASCII数据转化为hex格式
@param: DataASCII--ASCII数据区
        DataHex--转化为十六进制的数据区
@return:-1--失败,0--成功
@note:DataHex建议空间是DataASCII的三倍,函数中未检查空间大小
****************************************/
int uart_ASCII_ConvertHex_driver(char *DataASCII,char *DataHex)
{
    size_t LengthASCII = 0,i = 0,j = 0;

    if((DataASCII == NULL) || (DataHex == NULL))return -1;

    memset(DataHex,'\0',sizeof(DataHex));
    LengthASCII = strlen(DataASCII);

    for(i=0,j=0;(i < LengthASCII);i++)
    {
        DataHex[j] = uart_Number_ConvertHexCharacter(DataASCII[i]>>4);j++;
        DataHex[j] = uart_Number_ConvertHexCharacter(DataASCII[i]&0x0F);j++;
        DataHex[j] = ' ';j++;
    }
    return 0;
}

/****************************************
@function:hex数据转化为ASCII转格式
@param: DataHex--十六进制的数据区
        DataASCII--转化为ASCII数据区
@return:-1--失败,0--成功
@note:DataASCII空间等于DataHex空间即可,函数中未检查空间大小
格式:"02 03 ff 33"
****************************************/
int uart_Hex_ConvertASCII_driver(char* DataHex,char* DataASCII)
{
    size_t LengthHex = 0,i = 0,j = 0,k = 0;

    if((DataHex == NULL) || (DataHex == NULL))return -1;
    memset(DataASCII,'\0',sizeof(DataASCII));
    LengthHex = strlen(DataHex);
    for(i=0,j=0,k=0;i < LengthHex;i++)
    {
        if(DataHex[i] == 0x20)continue;     
        if(k == 0){DataASCII[j] = uart_HexCharacter_ConvertNumber(DataHex[i]);k++;}
        else{DataASCII[j] = DataASCII[j]*16 + uart_HexCharacter_ConvertNumber(DataHex[i]);j++;k=0;}
    }
    return 0;
}

/****************************************
@function:十六进制字符对应的数字值
@param:hex:十六进制字符['0'-'f']
@return:对应数字0-15
@note:'1'=1,'a'=10
****************************************/
char uart_HexCharacter_ConvertNumber(char hex)
{
    if(hex >= '0' && hex <= '9')return (hex - '0');
    else if(hex >= 'a' && hex <= 'f')return (hex - 'a' + 10);
	return 0;
}

/****************************************
@function:计算该值对应的十六进制字符
@param:数字0-15
@return:十六进制字符['0'-'f']
@note:'1'=1,'a'=10
****************************************/
char uart_Number_ConvertHexCharacter(char number)
{
    if(number >= 0 && number <= 9)return (number + '0');
    else if(number >= 10 && number < 16)return (number - 10 + 'a');
	return '0';
}

/****************************************
@function:字符串按十六进制格式检查
@param: data--数据区
@return:-2--不通过,首位置不通过,-1--中间位置不通过,0--通过
@note:若检查不通过,会自动截取至不满足位置添加字符串结束标志
****************************************/
int uart_StringCheckHex_driver(char *data)
{
    size_t LengthData = 0,i = 0;

    if(data == NULL)return -1;
    LengthData = strlen(data);
    for(i=0;i < LengthData;i++)
    {
        if(data[i] == 0x20){continue;}
        if(data[i] < '0' || data[i] > 'f')
        {
            data[i] = '\0';
            if(i == 0){return -2;}
            return -1;
        }
    }
    return 0;
}


uart_driver.h

#ifndef _uart_driver_H_
#define _uart_driver_H_
#ifdef __cplusplus
extern "C" {
#endif

typedef enum
{
    eParity_no = 0,
    eParity_odd,
    eParity_even,
    eParity_mark,
    eParity_space
}uart_parameter_parity_EnumDef;//校验位配置枚举

typedef enum
{
    eDataBits_5 = 5,
    eDataBits_6,
    eDataBits_7,
    eDataBits_8,
}uart_parameter_DataBits_EnumDef;//数据位配置枚举

typedef enum
{
    eStopBits_1 = 1,
    eStopBits_2
}uart_parameter_StopBits_EnumDef;//停止位配置枚举

typedef struct
{
    int port;//串口端口号;范围(0,+∞)
    unsigned __int64 BaudRate;//波特率:Valid Values: 110, 150, 300, 600, 1,200, 2,400, 4,800, 9,600, 14,400, 19,200, 28,800, 38,400, 56,000, 57,600, 115,200, 128,000, and 256,000
    uart_parameter_parity_EnumDef   parity; //校验位:见uart_parameter_parity_EnumDef
    uart_parameter_DataBits_EnumDef dataBits;//数据长度:见uart_parameter_DataBits_EnumDef
    uart_parameter_StopBits_EnumDef stopBits;//停止位:见uart_parameter_StopBits_EnumDef
    void (*Callback)(int,int,void*);//事件回调函数
    void (*Abnormal_Callback)(void);//异常回调函数,发生此事件时,串口会自动关闭
}uart_configuration_StructDef;//串口配置参数

typedef struct
{
    char status;//初值=0;串口状态:0--空闲,1--使用中
}uart_private_StructDef;//内部使用变量;注:定义时必须赋初值

typedef struct
{
    uart_configuration_StructDef configuration;
    uart_private_StructDef private;
}uart_driver_StructDef;//串口驱动结构体

int uart_open_driver(uart_driver_StructDef *uart);
void uart_close_driver(uart_driver_StructDef *uart);
int uart_StatusGet_driver(uart_driver_StructDef *uart);
void uart_ScanPort_driver(int panelHandle,int portID);
int uart_DataReceive_driver(int portNumber,char *data,size_t *BytesNumber);
int uart_DataReceive_IT_driver(int portNumber,int eventMask,char *data,size_t *BytesNumber);
int uart_DataTransmit_driver(uart_driver_StructDef *uart,char data[],size_t BytesNumber);
int uart_ASCII_ConvertHex_driver(char *DataASCII,char *DataHex);
int uart_Hex_ConvertASCII_driver(char* DataHex,char* DataASCII);
char uart_HexCharacter_ConvertNumber(char hex);
char uart_Number_ConvertHexCharacter(char number);
int uart_StringCheckHex_driver(char *data);

#ifdef __cplusplus
}
#endif
#endif


应用代码:
jpeg.h

#ifndef _jpeg_H_
#define _jpeg_H_
void jpeg_uart_init(void);
int jpeg();
#endif

jpeg.c

#include <ansi_c.h>
#include "jpeg_driver.h"
#include "uart_driver.h"

extern void disply(char *name);
void uart_COM_Callback(int portNumber, int eventMask, void *callbackdata);
void uart_Abnormal_Callback(void);


uart_driver_StructDef uart = \
{
    .private.status = 0,\
    .configuration.port = 3,\
    .configuration.BaudRate = 256000,\
    .configuration.parity = eParity_no,\
    .configuration.dataBits = eDataBits_8,\
    .configuration.stopBits = eStopBits_1,\
    .configuration.Callback = &uart_COM_Callback,\
    .configuration.Abnormal_Callback = &uart_Abnormal_Callback
};

#define duart_size (1024*40)
uint8_t uart_buffer[duart_size] = {0};
long int uart_pos = 0,jpeg_start = 0;;
uint8_t uart_flag = 0;

/****************************************************
@function:从设备0回调函数
@param:
@return:void
@note:
****************************************************/
void uart_COM_Callback(int portNumber, int eventMask, void *callbackdata)
{
    uint8_t data[1025] = {0};
    size_t BytesNumber = 1024,j = 0,z = 0;
    
    if(uart_DataReceive_IT_driver(uart.configuration.port, eventMask,data,&BytesNumber) < 0)return;
    if(BytesNumber == 0)return;

    for(j = 0;j < BytesNumber;j++)
    {
        if(uart_pos >= duart_size)uart_pos = 0;
        uart_buffer[uart_pos++] = data[j];
        if(uart_pos < 2)continue;
        if(jpeg_SegmentDetection_driver(uart_buffer[uart_pos-2],uart_buffer[uart_pos-1]) == eJPEG_Segment_Error)continue;

        if(uart_buffer[uart_pos-1] == eJPEG_Segment_SOI)
        {
            jpeg_start = uart_pos-2;
            uart_flag = 1;
        }
        else if(uart_buffer[uart_pos-1] == eJPEG_Segment_EOI)
        {
            if(uart_flag == 1)
            {
                //for(z = 0;z < (uart_pos-1 - jpeg_start + 1);z++)
                //{
                //    printf("%02x ",uart_buffer[jpeg_start + z]);
                //}
                jpeg_FileSave("out.jpg",&uart_buffer[jpeg_start],(uart_pos-1 - jpeg_start + 1));
                disply("out.jpg");
            }
            uart_flag = 0;
            uart_pos = 0;
        }
    }
}

/****************************************************
@function:从设备0异常回调函数
@param:
@return:void
@note:
****************************************************/
void uart_Abnormal_Callback(void)
{
    printf("%s\n",__func__);
}

//串口解析jpeg格式数据
void jpeg_uart_init(void)
{
    if(uart_open_driver(&uart) < 0)return;
}

//读取test.dat内的图像数据保存为照片+开启串口解析JPEG格式图像
int jpeg()
{
    jpeg_uart_init();return 0;
    long int len = 0;
    uint8_t *data = jpeg_FileRead("test.dat",&len);
    jpeg_ImageExtraction(data,len);
    free(data);
	return 0;
}


完整工程下载:
链接:https://pan.baidu.com/s/1OxSdYbS1G-PV4OPYAmjpjg
提取码:srvh

参考文档 jpeg图片格式详解:https://blog.csdn.net/yun_hen/article/details/78135122

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值