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_RECEIVESetCTSMode(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" {
#endiftypedef 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,000uart_parameter_parity_EnumDef   parity; //校验位:见uart_parameter_parity_EnumDefuart_parameter_DataBits_EnumDef dataBits;//数据长度:见uart_parameter_DataBits_EnumDefuart_parameter_StopBits_EnumDef stopBits;//停止位:见uart_parameter_StopBits_EnumDefvoid (*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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/18807.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

dubbo复习:(11)使用grpc客户端访问tripple协议的dubbo 服务器

一、服务器端依赖&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.…

头歌数据库备份与恢复

第一 mysql -uroot -p123123 -h127.0.0.1 < /data/workspace/myshixun/src/data.sql mysqldump -u root -p studb student> /student_bk.sql mysql -uroot -p123123 -h127.0.0.1 -e "create database studb2;" mysql -u root -p123123 studb2 < /student_bk…

【kubernetes】陈述式资源管理的kubectl命令合集

目录 前言 一、K8s 资源管理操作方式 1、声明式资源管理方式 2、陈述式资源管理方式 二、陈述式资源管理方式 1、kubectl 命令基本语法 2、查看基本信息 2.1 查看版本信息 2.2 查看资源对象简写 2.3 配置kubectl命令自动补全 2.4 查看node节点日志 2.5 查看集群信息…

01 Nginx安装部署(系列篇)

一、安装部署 1、Nginx的发行版本 常用版本分为四大阵营&#xff1a; Nginx 开源版 | https://nginx.org/&#xff1a;赤裸裸的Web服务器、反向代理、负载均衡&#xff08;功能少&#xff0c;开发难度大&#xff09; Nginx Plus 商业版 | https://www.nginx.com/&#xff1a;…

高职物联网专业嵌入式系统开发教学解决方案

前言 随着人工智能与物联网技术的深度融合&#xff0c;物联网&#xff08;AIoT&#xff09;已成为推动产业发展的重要力量。高职物联网专业作为培养技术人才的重要基地&#xff0c;面临着课程体系更新、教学内容优化的迫切需求。嵌入式系统开发作为物联网专业的核心课程之一&a…

[CVPR-24] HUGS: Human Gaussian Splats

本文提出一种新的数字人表征Human Gaussian Splats (HUGS)&#xff0c;可以实现新姿态和新视角生成&#xff1b;本文提出一种新的前向形变模块&#xff08;forward deformation module&#xff09;&#xff0c;在标定空间基于Gaussians表征数字人&#xff0c;并基于LBS学习如何…

秘钥托管技术简介

目录 前言 一、秘钥托管是什么&#xff1f; 二、秘钥托管技术简介 1. Skipjack算法 2. LEAF产生过程示意图 3. 对加密通信的法律实施存取过程 总结 前言 1993年4月&#xff0c;美国政府为了满足其电信安全、公众安全和国家安全&#xff0c;提出了托管加密标准EES (escro…

Aria2下载安装使用

目录 下载Aria2 配置创建 aria2.conf 文件创建 aria2.session 文件 Aria2的使用基础使用多源下载多线程下载后台下载配置文件启动 AriaNg下载安装AriaNg配置AriaNg使用 Tracker 列表 aria2 是一款免费开源跨平台且不限速的多线程下载软件&#xff0c;其优点是速度快、体积小、资…

慧尔智联携纷享销客启动CRM项目 推进客户经营升级与内外高效协作

智慧农业领军企业慧尔智联携手纷享销客&#xff0c;启动CRM客户经营管理系统项目。双方将深入合作&#xff0c;全面落实慧尔智联发展策略&#xff0c;持续提升数字化经营管理水平&#xff0c;实现内部团队信息化高效协作&#xff0c;以快速响应市场需求&#xff0c;提升客户满意…

开源集运wms系统

集运WMS系统是一种专为集运业务设计的仓库管理系统&#xff0c;它能够高效地处理来自多个来源的货物&#xff0c;优化存储和发货流程。 经过长时间的开发和测试&#xff0c;推出了我的集运WMS系统。它不仅具备传统WMS系统的所有功能&#xff0c;还针对集运业务的特点进行了特别…

HNU-计算机体系结构-小班讨论-GoogleTPU的发展历程与思考

因为对GPU比较感兴趣&#xff0c;故选择这个作为汇报课题。

JEPaaS 低代码平台 accessToTeanantInfo SQL注入漏洞复现

0x01 产品简介 JEPaaS低代码开发平台开源版 旨在帮助企业快速实现信息化和数字化转型。该平台基于可视化开发环境,让软件开发人员和业务用户通过直观的可视化界面来构建应用程序 ,而不是传统的编写代码方式。 用户可以在开发平台灵活各个图形化控件,以构建业务流程、逻辑和…

智能合约革命:Web3引领智能化商业的未来

随着区块链技术的日益成熟和普及&#xff0c;智能合约作为其重要应用之一&#xff0c;正在逐渐改变着商业世界的面貌。Web3作为下一代互联网的代表&#xff0c;以其去中心化、加密安全的特性&#xff0c;为智能合约的发展提供了无限可能&#xff0c;将智能合约应用于商业领域的…

对简单工厂模式、工厂方法模式、抽象工厂模式的简单理解

简单工厂模式 三部分组成 抽象类一些抽象类的具体实现类工厂类 把创建对象的任务交给一个工厂类来实现&#xff0c;对业务进行封装。 优点&#xff1a;实现了任务分离&#xff0c;客户端不用关心业务的具体实现&#xff0c;交由工厂来“生产”。 缺点&#xff1a;违背开闭原…

使用控制台方式部署sentinel

1.下载控制台jar包 2.运行jar包 java -jar sentinel-dashboard-1.8.0.jar 也可以通过编写批处理文件指定端口、用户名、密码&#xff1a; 客户端添加依赖&#xff08;后续整合springcloudalibaba时不需要此依赖&#xff09; 如修改了sentinel端口&#xff0c;需要添加客户端运…

Springboot项目搭建 jdk1.8

1.idea创建项目 2.项目配置 maven 编辑项目编码 删除无用文件 修改配置文件后缀&#xff0c;设置数据库 spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl:jdbc:mysql://localhost:3306/honey2024?useSSLfalse&useUnicodetrue&characterEncodingUT…

力扣每日一题 5/29

2981.找出出现至少三次的最长特殊子字符串I 题目&#xff1a; 给你一个仅由小写英文字母组成的字符串 s 。 如果一个字符串仅由单一字符组成&#xff0c;那么它被称为 特殊 字符串。例如&#xff0c;字符串 "abc" 不是特殊字符串&#xff0c;而字符串 "ddd&q…

Android9禁止某个app启动

禁止某个app通过开机广播自启动&#xff0c;覆盖住Launcher 代码位置 : frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java具体修改如下 public final int startActivityAsUser(IApplicationThread caller, String callingPackage,Inte…

详解 Scala 的运算符

一、Scala运算符的本质 Scala 运算符的本质是对象的方法 object TestOperator {def main(args: Array[String]): Unit {val n1: Int 10val n2: Int 20// 当调用对象的方法时&#xff0c;点. 可以省略val result1: Int n1.(n2)val result2: Int n1 (n2)println(result1)pr…

[Git] 如何在fork仓 从 主仓 更新代码

直接上干货 Step 1 添加主仓库为新的远程仓库&#xff1a;在终端或命令提示符中切换到你的本地仓库目录&#xff0c;然后运行以下命令以添加主仓库作为一个新的远程地址&#xff08;通常命名为upstream&#xff09;&#xff1a; git remote add upstream (主仓库的URL)Step 2 …