当前位置: 首页> 娱乐> 明星 > 电商初学者_国外服装网站_sem投放_seo01

电商初学者_国外服装网站_sem投放_seo01

时间:2025/7/13 17:40:41来源:https://blog.csdn.net/qlexcel/article/details/145455424 浏览次数:1次
电商初学者_国外服装网站_sem投放_seo01

作用

产品到客户现场出现异常情况,这个时候就需要一个日志记录仪、黑匣子,可以记录产品的工作情况,当出现异常时,可以搜集到上下文的数据,从而判断问题原因。

之前从网上买过,但是出现过丢数据的情况耽误了问题分析,自此以后就一直心有怀疑不敢全信它了,后面都是挂两个来交叉对比,生怕又被坑。于是索性乘自己有空来做一个。
在这里插入图片描述

软硬件开源地址:https://gitee.com/qlexcel/serial-port-data-logger

硬件

在这里插入图片描述

在这里插入图片描述
尺寸长38mm,宽21mm
在这里插入图片描述

使用

找一张TF卡,格式化为FAT32格式。没有的话可以网上买,8G的8块钱包邮。比如: TF卡

记录仪开机的时候会读取SD中的配置文件config.txt,获取用户配置。如果没有读取成功或者参数异常,就会恢复默认配置。
恢复默认配置后,config.txt文件内容就会被覆盖为以下内容:

baud:115200,stopbit:0,parity:0,filemb:30,time:0,timeout:4,filename:log,

来解释下配置的作用:

baud:115200,  //波特率  9600  115200  921600
stopbit:0,    //停止位    =0,1停止位  =1,0.5停止位  =2,2停止位  =3,1.5停止位
parity:0,     //奇偶校验位  =0,无校验  =2,偶校验  =3,奇校验
filemb:30,    //日志文件最大大小,单位MB
time:0,       //是否添加时间戳  =1,添加  =0,不添加
timeout:4,    //超时时间  超过此时间没有收到新数据,就会关闭日志文件,此时可以安全拔出SD卡
filename:log, //日志文件名 

LED灯的作用:
绿灯闪烁表示接收到数据。
蓝灯亮起表示正在保存数据到SD卡。
蓝灯快闪表示出现故障。

软件

如下是main函数代码,功能实现都在这里

#include "bsp.h"/*
最好每次抓数据时,把SD中的log文件清空
*//******************************************* 宏定义区域 ****************************************/
#define QL_SUCCESS          0       //函数执行成功
#define QL_FAIL             1       //函数执行失败
#define QL_ERROR_SD_CARD    2       //SD卡故障
#define QL_ERROR_FILE_SYS   3       //文件系统故障#define CFG_FILE_NAME "config.txt"  //配置文件名
#define FILE_NAME     "log"         //默认的日志文件名
#define DEBUG_STA 1                 //=1,打开调试模式   =0,关闭调试模式
#define WR_BUF_LEN 14000            //写数据buf大小/******************************************* 变量定义区域 ****************************************/
FATFS fs;
FIL fsrc; 
uint8_t wrbuffer[WR_BUF_LEN];        //写数据buf 
//                      1   2       4   5       7   8      10  11  
uint8_t  Date[14]={'[','0','0','_','0','1',':','0','1',':','0','1',']',0};
uint8_t  TimeStamp;                  //是否添加时间戳  =1,添加  =0,不添加
uint8_t  Day=0;                      //天数
uint8_t  PastSecond;                 //多长时间没有接收到数据,单位秒
uint8_t  TimeOut=4;                  //超时时间
uint8_t  FileOpenSta=0;              //日志文件打开状态
uint32_t BaudRate=115200;            //波特率
uint8_t  StopBits=0;                 //停止位    =0,1停止位  =1,0.5停止位  =2,2停止位  =3,1.5停止位
uint8_t  Parity=0;                   //奇偶校验位  =0,无校验  =2,偶校验  =3,奇校验
uint16_t Head,Tail,len;
uint32_t TotalLen=0,FileMaxLen;
uint32_t len_bk,DateWr,DateWrOld;
char  FileName[11];                  //日志文件名字
uint8_t FileNameIndex=0;             //日志文件名字编号
uint32_t LedG_Blink_Cnt;             //接收到数据绿灯闪烁计数
uint8_t  LedG_Blink_Flg;             //接收到数据绿灯闪烁标志/******************************************* 函数声明区域 ****************************************/
uint8_t Filesystem_Handle(void);
uint8_t GetstrstrValue(uint8_t* str, char* substr, uint8_t* out, uint16_t MaxLen);
uint32_t MyStr2Int(uint8_t* str, uint8_t dot);int main(void)   //监视下文件系统每次写扇区个数
{  	uint8_t res,tmp;mGPIO_Init();	RTC_Init();res=Filesystem_Handle();UART_Init();printf("/** Uart Data Saver V1.0**/\r\n");if(res==QL_ERROR_SD_CARD)printf("SD Card Error!\r\n");else if(res==QL_ERROR_FILE_SYS)printf("File System Error!\r\n");else if(res)printf("Other Error!\r\n");elseprintf("Init ok!\r\n");while(res)          //初始化不成功,就死循环闪灯提示{		gd_eval_led_toggle(LED_BLUE);delay_1ms(200);}		LED_G_OFF();LED_B_OFF();while(1){		Head=RX_BUF_LEN-DMA_CHCNT(X1_UART_DMA, X1_UART_DMA_CH_RX);  //DMA已经接收到的数据个数 		if(Head!=Tail)  //如果接收到数据{wrbuffer[len++]=rxbuffer[Tail++];if(Tail==RX_BUF_LEN) Tail=0;if(TimeStamp && DateWrOld!=DateWr)                      //时间戳打开 且 写入的时间发生了改变{if(wrbuffer[len-1]=='\n' || wrbuffer[len-1]=='\r')  //遇到换行,写入一次时间{tmp=0;while(tmp<13){wrbuffer[len++]=Date[tmp++];DateWrOld=DateWr;}
#if DEBUG_STA					printf("%s\r\n",Date);
#endif					}}PastSecond=0;LedG_Blink_Flg=1;   //接收到数据,LED闪烁提示}if(len>(WR_BUF_LEN-5))  //当接收数据比较多时,就写入一次SD卡。数据写完后,日志文件不关闭{LED_B_ON();if(FileOpenSta==0)  //如果日志文件没有打开{res = f_open(&fsrc,FileName,FA_WRITE);f_lseek(&fsrc, f_size(&fsrc));FileOpenSta=1;}res = f_write(&fsrc,wrbuffer,len,&len_bk);if(res) break;printf("wr%d\r\n",len);	TotalLen+=len;if(TotalLen>FileMaxLen)   //如果数据大小超过了文件最大{tmp=strlen(FileName);  //文件编号+1FileNameIndex++;FileName[tmp-7]=FileNameIndex/100+'0';FileName[tmp-6]=FileNameIndex%100/10+'0';FileName[tmp-5]=FileNameIndex%10+'0';f_close(&fsrc);res = f_open(&fsrc,FileName,FA_WRITE|FA_OPEN_ALWAYS);  //打开新文件f_lseek(&fsrc, f_size(&fsrc));TotalLen=0;}len=0;	LED_B_OFF();						}else if(PastSecond>TimeOut && (len>0 || FileOpenSta==1))  //没有新数据一段时间后,如果还有数据没写入,就立即写入{                                                          //或者日志文件处于打开状态,就关闭LED_B_ON();if(len>0)  //有数据没写入,就立即写入{if(FileOpenSta==0)  //没有打开文件{	res = f_open(&fsrc,FileName,FA_WRITE);f_lseek(&fsrc, f_size(&fsrc));FileOpenSta=1;				}				res = f_write(&fsrc,wrbuffer,len,&len_bk);if(res) break;}if(FileOpenSta==1){	f_close(&fsrc);FileOpenSta=0;}			printf("wr%d\r\n",len);	TotalLen+=len;len=0;	LED_B_OFF();			}if(LedG_Blink_Flg)  //接收到数据,LED闪烁提示{LedG_Blink_Cnt++;if(LedG_Blink_Cnt>30000){LedG_Blink_Cnt=0;if(gpio_input_bit_get(LED_G_PORT, LED_G_PIN))  //如果IO是高,LED灭的状态{LED_G_ON();}else  //如果IO是低,LED亮的状态{LED_G_OFF();LedG_Blink_Flg=0;}}}if(RTC_CTL & RTC_FLAG_SECOND)          //秒中断标志{RTC_CTL &= ~RTC_FLAG_SECOND;       //清除中断标志DateWr=(RTC_CNTH << 16)|RTC_CNTL;  //获取当前时间if (DateWr == 86399)               //当时间到达23:59:59时清零,天数加1{RTC_CTL |= RTC_CTL_CMF;RTC_CNTH=0;RTC_CNTL=0;RTC_CTL &= ~RTC_CTL_CMF;Day++;rtc_lwoff_wait();}	PastSecond++;Date[1]=Day%100/10+'0';Date[2]=Day%10+'0';			tmp=DateWr/3600;     //hoursDate[4]=tmp/10+'0';Date[5]=tmp%10+'0';tmp=DateWr%3600/60;  //minutesDate[7]=tmp/10+'0';Date[8]=tmp%10+'0';			tmp=DateWr%60;       //seconds	Date[10]=tmp/10+'0';Date[11]=tmp%10+'0';	
//			printf("%s\r\n",Date);}			}while(1)  //当文件系统有问题,就会跳出上面循环到达这里,闪灯提示{		gd_eval_led_toggle(LED_BLUE);delay_1ms(50);}	
}#define CONFIG_DEFAULT_LEN 71
static const char CONFIG_DEFAULT[CONFIG_DEFAULT_LEN]="baud:115200,stopbit:0,parity:0,filemb:30,time:0,timeout:4,filename:log,";
uint8_t Filesystem_Handle(void)
{uint8_t res,i;res=SD_Init();if(res) return QL_ERROR_SD_CARD;          //SD卡有问题res=f_mount(&fs,"0:",1);if(res!=FR_OK) return QL_ERROR_FILE_SYS;  //文件系统有问题res = f_open(&fsrc,CFG_FILE_NAME,FA_READ); //以只读方式打开配置文件if(res==FR_OK)                             //打开成功,说明文件存在{res = f_read(&fsrc,rxbuffer,200,&len_bk);f_close(&fsrc);if(res==FR_OK && len_bk>50)            //数据读取成功且大小正常{res |= GetstrstrValue(rxbuffer,"baud:",wrbuffer,10);      //波特率BaudRate=MyStr2Int(wrbuffer,0);res |= GetstrstrValue(rxbuffer,"stopbit:",wrbuffer,10);   //停止位StopBits=MyStr2Int(wrbuffer,0);res |= GetstrstrValue(rxbuffer,"parity:",wrbuffer,10);    //校验位Parity=MyStr2Int(wrbuffer,0);res |= GetstrstrValue(rxbuffer,"filemb:",wrbuffer,10);    //文件大小 FileMaxLen=MyStr2Int(wrbuffer,0);res |= GetstrstrValue(rxbuffer,"time:",wrbuffer,10);      //时间戳   TimeStamp=MyStr2Int(wrbuffer,0);res |= GetstrstrValue(rxbuffer,"timeout:",wrbuffer,10);   //超时事件TimeOut=MyStr2Int(wrbuffer,0);res |= GetstrstrValue(rxbuffer,"filename:",wrbuffer,10);  //日志文件名strcpy(FileName,(char*)wrbuffer);}elseres=1;}if(res!=FR_OK)  //如果配置文件读取失败,使用默认配置参数{BaudRate=115200;StopBits=0;Parity=0;FileMaxLen=30;TimeStamp=0;TimeOut=4;strcpy(FileName,FILE_NAME);res = f_open(&fsrc,CFG_FILE_NAME,FA_WRITE|FA_CREATE_ALWAYS);      //把默认参数写入SD卡res |= f_write(&fsrc,CONFIG_DEFAULT,CONFIG_DEFAULT_LEN,&len_bk);		f_close(&fsrc);if(res!=FR_OK) return QL_FAIL;	for(i=0;i<100;i++)  //配置参数被恢复默认了,要闪灯提示,避免用户不知道导致数据丢{		gd_eval_led_toggle(LED_BLUE);delay_1ms(50);gd_eval_led_toggle(LED_GREEN);}			}FileMaxLen<<=20;  //总大小单位由MB变成字节i=strlen(FileName);FileName[i]  =FileNameIndex/100+'0';     //日志文件名编号,第1个文件名是log000.txt,当超过文件大小,保存到第2个文件log001.txtFileName[i+1]=FileNameIndex%100/10+'0';FileName[i+2]=FileNameIndex%10+'0';FileName[i+3]='.';FileName[i+4]='t';FileName[i+5]='x';FileName[i+6]='t';FileName[i+7]=0;res = f_open(&fsrc,FileName,FA_OPEN_ALWAYS);  //如果日志文件存在,则打开该文件。 如果没有,将创建一个新文件。f_close(&fsrc); 	if(res!=FR_OK) return QL_FAIL;elsereturn QL_SUCCESS;
}/*********************************************************************************************************
* 功能说明: 在字符串str中匹配子字符串,并获取子字符串后面的字符串
*********************************************************************************************************/
uint8_t GetstrstrValue(uint8_t* str, char* substr, uint8_t* out, uint16_t MaxLen)
{uint16_t len = 0;char *p1,*p2;while(*str != 0){p1 = (char*)str;p2 = substr;while(*p1 && *p2 && *p1 == *p2){p1++;p2++;}if (*p2 == 0){p2 = (char*)out;while (*p1 != ','){*p2 = *p1;p1++;p2++;len++;if (len >= MaxLen)return QL_FAIL;}*p2 = 0;return QL_SUCCESS;}str++;}return QL_FAIL;
}/*********************************************************************************************************
* 功能说明: 字符串转整型数
* 形    参: str:字符串
*           dot:小数点  =0表示不放大  =2表示放大100倍
* 返 回 值: 整型数
*********************************************************************************************************/
uint32_t MyStr2Int(uint8_t* str, uint8_t dot)
{int out = 0;while (*str != 0){out *= 10;out += *str - '0';str++;if (*str == '.'){if (dot == 2){str++;out *= 10;if (*str >= '0' && *str <= '9')out += *str - '0';str++;out *= 10;if (*str >= '0' && *str <= '9')out += *str - '0';return out;}elsereturn out;}}if (dot == 2)out *= 100;return out;
}

可以看到main函数中,先初始化IO、RTC后,就执行Filesystem_Handle函数。

	mGPIO_Init();	RTC_Init();res=Filesystem_Handle();UART_Init();printf("/** Uart Data Saver V1.0**/\r\n");if(res==QL_ERROR_SD_CARD)printf("SD Card Error!\r\n");else if(res==QL_ERROR_FILE_SYS)printf("File System Error!\r\n");else if(res)printf("Other Error!\r\n");elseprintf("Init ok!\r\n");while(res)          //初始化不成功,就死循环闪灯提示{		gd_eval_led_toggle(LED_BLUE);delay_1ms(200);}		

在Filesystem_Handle函数中初始化SD卡,然后读取配置文件config.txt中的内容来获取用户配置,如果没有读取成功就使用默认配置。
一切正常就进入while循环。在while循环中不停读取串口buf中的数据到wrbuffer中,当wrbuffer大小够大时就写入SD卡。
在这里插入图片描述

测试

方法1:不同波特率发送1M大小txt文件给串口数据记录仪,对比原始文件和日志文件内容。

方法2:单片机发送随机数据给两个串口数据记录仪,长时间测试后对比两个日志文件内容。

关键字:电商初学者_国外服装网站_sem投放_seo01

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: