Stm32_标准库_期末设计_温度测量光照测量手机与芯片通信实现信息的更新
目录
- 前言:
- 1.接线&效果&功能:
- 2. 实现:
- 1、手机与芯片单向通信:
- (1) 确保接收数据的完整性:
- (2) 判断传输数据的合法性:
- (3) 对数据合理的分割整合:
- (4) 实现过程产生的重大BUG及解决方法:
- 2、时间&日期的实现:
- 3、温度&光照的测量:
- 4、OLED显示优化:
- 5、主函数的设计与布局:
- 3. 总结:
- 4.程序源码:
前言:
期末设计预期的效果是整个系统能对环境温度、环境的光照情况进行测量及显示,并且能对时间及日期进行显示。时间与日期的控制不再打算用按键进行修改,取而代之用蓝牙模块实现手机与蓝牙模块之间单向通信,即手机向蓝牙模块发送当前的时间或日期,蓝牙模块接受数据,通过内部代码对数据进行筛选与解析,最后更新芯片自身数据为手机发送的数据。
1.接线&效果&功能:
1、接线:
1、光敏传感器AO端口接GPIO_PA_0
2、热敏传感器AO端口接GPIO_PA_1
3、蓝牙模块端口RXD接GPIO_PA_9
4、蓝牙模块端口TXD接GPIO_PA_10
2、效果:
3、功能:
1、实时监控当前环境的温度范围为[- 20 ℃,+ 99 ℃]
2、实时监控当前环境的光照强度,光照强度由低到高为[0 , 100]
3、显示时间与日期
4、能接收手机传输的信息并整合更新自己的日期与时间
2. 实现:
1、手机与芯片单向通信:
主要利用了Stm32自带的串口通信功能,这个跟着网上大佬学就可以了
除此之外手机与芯片之间的单向通信还要解决以下几个问题:
1、如何确保接收数据的完整性?
2、如何判断传输数据的合法性?
3、如何对数据合理的分割整合?
解答如下:
—— 2023/10/16
(1) 确保接收数据的完整性:
首先需要注意的就是数据之所以会出现丢失,主要原因在于手机向接受端发送信息时,接收端不能及时接受信息,以至于前一个数据还未来的及接受就被后来的数据覆盖
数据不能被及时接收的原因:
网上常用数据接收代码:
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{Serial_RxData = USART_ReceiveData(USART1); //一个一个接收Serial_RxFlag = 1;USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
由上述串口接收数据中断函数可以看出,触发中断后数据总是一个字节逐个被Serial_RxData
变量接收
接着标记标志位Serial_RxFlag
,主函数发现标志位变化,才会接受并储存Serial_RxData
上的数据
这个逻辑看似没有问题,但漏洞在于,我们的主函数不可能时刻判断标志位的值是否变化吧?朴素的说主函数不可能就执行判断标志位是否变化这一个语句吧?正是由于主函数在执行其他语句的时候导致没能时刻观察标志位的变化,而导致数据不能被立即接收,最终导致了数据丢失
那么解决方向就显而易见了,即如何做到数据能在中断发生的时候就立即接收呢?
答案就是数组
优化代码:
void USART1_IRQHandler(void)//中断函数
{if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET){news[I] = USART_ReceiveData(USART1);//读数据Serial_RxFlag = 1;//至标志位为有数据I ++;USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}
在中断产生的时候就立即用数组进行接收,同时标记标志位
主函数发现标志位变化了,等待一会就可以获取数组,取出传输方发送的全部信息了
(2) 判断传输数据的合法性:
传输方发送的信息不可能都是符合标准的,那么如何对数据进行筛选就显得及其重要
首先对我们需要的正确信息进行分析其特点:
例如需要获取的正确信息如下:日期:2023/10/17时间:21:57:55
分析上述两个典型数据,可以发现日期的特点是数据里存在/
,数据时间特点是有:
,那么第一次筛选条件就是判断接收数据是否存在上述任意一种符号。
这个在数据传输阶段就可以用两个标志位判断:
if(news[i] == '/') flagDate = 1;
if(news[i] == ':') flagTime = 1;
接下来摆在面前的就是假若筛选后的数据里出现超过两个/
或:
符号的时候
再进一步讲上若传入的数据符号为两个,但是传入的时间为25:15:80
阁下又应该如何应对?
要解决上述问题还是要对传入数据的特点进行细节分析:
拿日期 2023/10/17 进行分析,其中/
符号出现了两次我们完全可以用一个cnt
在拆解数据的过程中进行计数,若最后cnt
的大小不等于2的时候那么这个数据就会被判断为不合法这样符号问题就解决了
—— 2023/10/17
(3) 对数据合理的分割整合:
那么又如何对年份,月份,天数、进行判别呢?
这就需要将数据进行切割了拿2023/10/17
示范,分析数据,巧妙的是在2023出现的时候cnt = 0
,也就是在2023
之前没有出现/
而到10
出现的时候cnt = 1
,最后17
出现的时候自然cnt = 2
。恍然大悟用一个updateDate[cnt]
分别对数据进行储存即可updateDate[0] = 2023、updateDate[1] = 10、updateDate[2] = 17
再对这三个数据分别分析就可以最终判断传入的数据是否合法了!
实现代码:
uint8_t Function_DateState(unsigned int *updateDate, char *News){uint8_t cnt = 0;uint8_t i = 0;uint8_t end = Serial_GetI();char month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};while(i < end){if(News[i] == '/') {cnt ++;i ++;if(cnt >= 3) {return 0;}continue;}updateDate[cnt] = updateDate[cnt]* 10 + (News[i] - '0');i ++;}if(cnt != 2) return 0;if(Function_Numlength(updateDate[0]) >= 5 || updateDate[0] > 9999 || updateDate[0] == 0) return 0;if((updateDate[0] % 4 == 0 && updateDate[0] % 100 != 0 )|| updateDate[0] % 400 == 0) month[2] = 29;else month[2] = 28;if(Function_Numlength(updateDate[1]) >= 3 || updateDate[1] > 12 || updateDate[1] == 0) return 0;if(Function_Numlength(updateDate[2]) >= 3 || updateDate[2] > month[updateDate[1]]|| updateDate[2] == 0) return 0;Time_GetArrayMonth()[2] = month[2];//这里年份也会发生变化,要修改原有数据return 1;}
(4) 实现过程产生的重大BUG及解决方法:
上述理论成立,接下来就是动手实践了。以下是在对功能以及细节实现过程中产生重大BUG原因的解答以及解决方法的揭秘:
为了让主函数main函数更加简洁,我将数据传输的侦测,处理以及更新都封装在主函数以外的文件中,主函数引用其头文件即可调用我提前封装好的函数,也就是因为封装这些函数,所以产生一些小问题以下列函数为例:
返回数据函数:
char * Serial_returnNews(void){//返还一个数组char * array;uint8_t i = 0;array = (char *) malloc(sizeof(char) * 100);Delay_ms(300);//等待数据传输完while(i < I){//复制if(news[i] == '/') flagDate = 1;if(news[i] == ':') flagTime = 1;array[i] = news[i];i ++;}return array;
}
1、多次传输数据芯片出现卡机现象:
这个函数目的是将接收端存放在数组内的数据,传送至数据处理端,这里使用malloc
创建了一个char数组将news数值的数据copy过来并作为返地址,由于此函数是个返还类型的函数,所以没办法及时清理掉这个新创建的array
数组,但这不代表不需要清理
若不采取情理,运行程序,手机端在向芯片连续发送几次信息后,显示屏上的就会卡住,任凭怎么输入都没有反应。
究其原因就是因为大量因创建数组产生的地址泄露,导致最后芯片地址耗尽,停止工作
解决方法:
free(News);//释放空间必须释放否者发生地址紊乱,直接卡机
2、返回数据函数被离奇执行两次:
解决上述问题后,数据传输会卡机的现象就没有了,但是再多测试几次的时候,却惊奇的发现传输的数据和接收的数据还是会有误差,查看news
数组的时候发现数据并没有丢失?!但传递到数据处理端就有问题?然而我的返还数组函数并没有问题啊,这个bug就很玄学了。
经过不懈排查体调试最终发现传输数据的时候,char * Serial_returnNews(void)
被执行了两次?!这是我用cnt变量计数得来的,这个函数又没和别的中断函数重名,为啥调用一次执行两次?再说偏偏还执行两次,真是邪门…
重新更改调试方向,我将目标放在了主函数:
if(Serial_GetRxFlag() == 1) //时刻监控标志位
这条语句是监控数据是否传输完成的,若传输完成则Serial_GetRxFlag()
会返回1值并自动清0,主函数进入if语句内并处理数据
uint8_t Serial_GetRxFlag(void)//读取标志位后自动青除
{if (Serial_RxFlag == 1){Serial_RxFlag = 0;return 1;}return 0;
}
再结合着中断传输数据函数判断:
void USART1_IRQHandler(void)//中断函数
{if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET){news[I] = USART_ReceiveData(USART1);//读数据Serial_RxFlag = 1;//至标志位为有数据I ++;USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}
看似没有问题,但要知道中断函数在接受数据的时候是一字节一字节的接受,当传输一串数据的时候Serial_RxFlag = 1
语句就是一个持续的过程,也就是当传输一串数据的时候主函数if虽然获取了标志位,并将其制0,但后续数据继续传输的时候中断函数内的Serial_RxFlag = 1
,仍会继续将标志位制1,这就是为什么if语句还会执行一次
解决方法在if语句结束的时候再次调用制0函数:
Serial_GetRxFlag();//制零否则if循环将会被执行两次
3、数据显示乱码:
这个问题单纯是因为使用中间变量接收数据完毕后没有将其恢复初始化,内部存有上次传输的数值,导致数据叠加乱码
解决方法:
unsigned int updateTime[] = {0, 0, 0};unsigned int updateDate[] = {0, 0, 0};
2、时间&日期的实现:
时间、日期主要分别存入对应数组中,需要更改的话直接更改对应数组即可
unsigned int time[] = {22, 59, 30};
unsigned int date[] = {2023, 12, 31};
char month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
主函数需要提取对应数组的话,直接调用提取数组函数即可:
unsigned int * Time_GetArrayTime(void){return time;
}unsigned int * Time_GetArrayDate(void){return date;
}
char * Time_GetArrayMonth(void){return month;
}
时间计数,采用的是芯片计数器功能,在记满相应数值,达到1s触发中断函数,对时间日期进行更新
中断函数:
void TIM2_IRQHandler(void){//定时器2//主要运用时间更新if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除标志位Time_Control(time, month, date);}
}
注意:时间显示中断抢占优先级要设置的比,串口输入中断等级低一点,否者串口传入数据会由于时间中断函数与其抢占CPU导致接受数据丢失,中断函数的名字及类型最好不要更改避免产生相应不必要的BUG
时间中断等级设置:
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
—— 2023/10/19
3、温度&光照的测量:
主要用到了Stm32的数据转换功器(ADC)
通俗来说,正常的GPIO口只能读取0或1即低电平和高电平,而在低电平与高电平这一区间内的电平却无法描述,Stm32的ADC正可以解决这个问题,朴素的来讲ADC能让GPIO口成为一个电压表
而温度传感器,光敏传感器就是因为温度或光照的变化导致内部电阻阻值发生变化,最后导致其输出电压发生变化,GPIO口通过读取这些电压的具体量,再由人为对这些数据量做一些数据处理就能转换成我们想要的摄氏度、光照强度,以下是数据转换公式:
1.光照模拟量转实际光照强度:
uint16_t Function_RealityADLight(uint16_t ADCnum){//获取光照强度return 100 - ADCnum / 40;
}
2.温度模拟量转实际摄氏度:
这个网上找的公式不能用,问了人家说只知道成线性关系,所以带入两组数据自己测了一个函数关系用起来还不错凑活着用:
int32_t Function_RealityTmperature(uint16_t Vout){//获取实际温度double T = 0;//获取的实际温度T = -0.0423 * Vout + 105 + 0.5;//模拟电压转实际温度公式return (int32_t) T;
}
这个温度可以测出负温度,为了严谨,用了double变量转换温度
4、OLED显示优化:
OLED:
我对OLED的理解就是它一行有128个点,显示一个字母需要消耗这一行其中8个点,且字符是分两部分打印,上一半和下一半,一行最多打印16个字符,最多能打印四列
OLED程序源中提供了输出字符、清屏、以及输出符号类数字等功能,还是相当丰富的
但是为了让显示屏显示光照、温度的效果达到最佳,还是迫切需要对OLED库中扩充一些功能
1.解决输出无符号数字不足规定长度自动补零的缺陷:
OLED提供的源显示数据函数:
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
这个函数需要提前写入你要显示的数字长度,后续数字长度不足会在前面补零
如上述显示及其影响美观,所以添加一个能实时监控输入数字长度的函数:
uint8_t Function_Length(uint16_t num){uint8_t length = 0;if(num == 0) return (uint8_t) 1;while(num > 0){num = num / 10;length = length + 1;}return length;
}
这不学的算法就用上了,注意0的长度是1
由于温度有正有负,所以需要一个检测有符号数字长度的函数:
uint8_t Function_SignedNum_Length(int32_t num){uint8_t length = 1;//符号位占1位if(num == 0) return (uint8_t) 1;if(num < 0) num = - num;while(num > 0){num = num / 10;length = length + 1;}return length;
}
由于OLED库函数的输出有符号数字事先未考虑计算符号长度,而是提前添加正负号,所以其也得修改
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{uint8_t i;uint32_t Number1;Length = Length - 1;if (Number >= 0){OLED_ShowChar(Line, Column, '+');Number1 = Number;}else{OLED_ShowChar(Line, Column, '-');Number1 = -Number;}for (i = 0; i < Length; i++) {OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');}
}
2.解决数据刷新造成的数据显示不连贯效果:
OLED数据刷新是采用覆盖式的例如上一次数据显示19
这一次要写入9
的时候不足位会补0
也就是显示09
,但由于上述操作让其位数不足不会补0,也就是说显示的将不会是09
而是显示99
即1被这次要写入的9覆盖掉了而后面的数据却没有被覆盖了,这涉及的就不是美不美观的问题了,直接就显示错了数据
所以必须要将后面的数清理掉,OLED库函数提供的只有清屏函数,简单粗暴全部清理掉,再全部写入
这样做有很多不便之处,原因在于整体清除刷新需要大量时间OLED显示起来整体就不连贯影响美观,还有就例如日期数据就没必要一直刷新,只有天数变了才需要刷新,没必要放在while循环内。所以迫切需要一个能清除某片区域的函数,以便能为美化OLED显示以及后续代码的优化提供功能支持
清除特定区域函数:
void OLED_ClearLocation(uint8_t row, uint8_t begin, uint8_t end)
{ uint8_t i, j;for (j = row * 2 - 2; j < row * 2; j++){OLED_SetCursor(j, begin * 8);for(i = begin * 8; i < end * 8; i ++){OLED_WriteData(0x00);}}
}
根据清屏函数重写一个清除某区域的函数,参数分别表示要删除的行,以及从哪里清除,到哪里结束。
3.添加OLED显示汉字功能:
利用取模软件对想要输出汉字进行取模,根据已有输出字符函数原理创建输出汉字函数
封装汉字数组:
const uint8_t OLED_F10x16[][32] ={0x10,0x60,0x02,0x8C,0x00,0x00,0xFE,0x92,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,0x00,
0x04,0x04,0x7E,0x01,0x40,0x7E,0x42,0x42,0x7E,0x42,0x7E,0x42,0x42,0x7E,0x40,0x00,/*"温",0*/0x00,0x00,0xFC,0x24,0x24,0x24,0xFC,0x25,0x26,0x24,0xFC,0x24,0x24,0x24,0x04,0x00,
0x40,0x30,0x8F,0x80,0x84,0x4C,0x55,0x25,0x25,0x25,0x55,0x4C,0x80,0x80,0x80,0x00,/*"度",1*/0x40,0x40,0x42,0x44,0x58,0xC0,0x40,0x7F,0x40,0xC0,0x50,0x48,0x46,0x40,0x40,0x00,
0x80,0x80,0x40,0x20,0x18,0x07,0x00,0x00,0x00,0x3F,0x40,0x40,0x40,0x40,0x78,0x00,/*光,2*/0x00,0xFE,0x42,0x42,0x42,0xFE,0x00,0x42,0xA2,0x9E,0x82,0xA2,0xC2,0xBE,0x00,0x00,
0x80,0x6F,0x08,0x08,0x28,0xCF,0x00,0x00,0x2F,0xC8,0x08,0x08,0x28,0xCF,0x00,0x00,/*"照",3*/0x00,0x08,0x30,0x00,0xFF,0x20,0x20,0x20,0x20,0xFF,0x20,0x20,0x22,0x2C,0x20,0x00,
0x04,0x04,0x02,0x01,0xFF,0x80,0x40,0x30,0x0E,0x01,0x06,0x18,0x20,0x40,0x80,0x00,/*"状",4*/0x00,0x04,0x84,0x84,0x44,0x24,0x54,0x8F,0x14,0x24,0x44,0x84,0x84,0x04,0x00,0x00,
0x41,0x39,0x00,0x00,0x3C,0x40,0x40,0x42,0x4C,0x40,0x40,0x70,0x04,0x09,0x31,0x00,/*"态",5*/
};
显示汉字函数:
void OLED_ShowCHINESE(uint8_t Line, uint8_t Column, uint8_t Num)
{uint8_t i;uint8_t wide = 16;//字宽OLED_SetCursor(( Line - 1 ) * 2, ( Column - 1 )* wide); //参数1:把光标设置在第几页. 参数2:把光标设置在第几列for (i = 0; i < wide; i++){OLED_WriteData(OLED_F10x16[Num][i]); //显示上半部分内容}OLED_SetCursor(( Line - 1 ) * 2 + 1,( Column - 1) * wide); for (i = 0; i < wide ; i++){ OLED_WriteData(OLED_F10x16[Num][i+wide]); //显示下半部分内容}}
参考来源:OLED显示汉字及屏幕滚动
5、主函数的设计与布局:
为了使主函数布局清晰,所以对主函数的代码进行了最大可能的优化,采用函数嵌套函数的方式,反正Stm32函数已经够多了我再添加一点也很核理,这样做的优点就是思路清晰,后续添加新功能的时候也很方便明了,缺点就是查bug的时候得来回跳转,不过我是确认没有大bug的情况下才开始优化的
主函数:
#include "ADC.h"
#include "OLED.h"
#include "Time.h"
#include <stdio.h>
#include "Delay.h"
#include <stdlib.h>
#include "Serial.h"
#include "Function.h"
#include "stm32f10x.h" char *News = NULL; //存数据int main(void){AD_Init(); //开启ADC
OLED_Init(); //开启显示器
Time_Init(); //开启计时器
Serial_Init(); //开启串口允许接收数据
Function_ShowTransmit(); //显示接收数据的状态
Time_ShowDate(Time_GetArrayDate()); //显示日期while(1){Time_Show(Time_GetArrayTime()); //时刻显示温度ADC_printf(ADC_Channel_0, ADC_Channel_1); //时刻获取温度&光照强度并显示if(Serial_GetRxFlag() == 1){ //时刻监控标志位News = Serial_returnNews(); //获取传输的数据Function_DP(Serial_GetFlagTime(), Serial_GetFlagDate(), Time_GetArrayTime(), Time_GetArrayDate(), News); //对获取的数据进行筛选处理并自我更新Serial_StateRecovery(News); //数据恢复初始化}}
}
与主函数搭配的库函数:
3. 总结:
明白了学习嵌入的过程就是理解并能灵活使用其提供的库函数的过程
要有自己的创新与解决问题的能力
将功能尽可能封装,能使代码思路更加清晰
4.程序源码:
链接:https://pan.baidu.com/s/1WsZ7dTRUMHRa8jaXDtmrpA?pwd=ws6f
提取码:ws6f
—— 2023/10/18
相关文章:

Stm32_标准库_期末设计_温度测量光照测量手机与芯片通信实现信息的更新
目录 前言:1.接线&效果&功能:2. 实现:1、手机与芯片单向通信:(1) 确保接收数据的完整性:(2) 判断传输数据的合法性:(3) 对数据合理的分割整合:(4) 实现过程产生的重大BUG及解决方法: 2、时间&日…...

JavaScript 的类型和值
JavaScript 的类型和值 1. 类型 1.1 七种内置类型 空值(null)未定义(undefined)布尔值(boolean)字符串(string)数字(number)对象(object)符号&…...

Kotlin Compose Multiplatform 跨平台开发实践之加入 iOS 支持
前言 几个月前 Compose Multiplatform 的 iOS 支持就宣布进入了 Alpha 阶段,这意味着它已经具备了一定的可用性。 在它发布 Alpha 的时候,我就第一时间尝鲜,但是只是浅尝辄止,没有做过多的探索,最近恰好有点时间&…...

【小黑嵌入式系统第四课】嵌入式系统硬件平台(二)——I/O设备、通信设备(UARTUSB蓝牙)、其他(电源时钟复位中断)
上一课: 【小黑嵌入式系统第三课】嵌入式系统硬件平台(一)——概述、总线、存储设备(RAM&ROM&FLASH) 文章目录 一、I/O设备1. 定时器/计数器2. ADC和DAC3. 人机接口设备3.1 键盘3.2 LCD显示器3.3 触摸屏 二、通信设备1. 通…...

报错:AttributeError: module ‘tensorflow‘ has no attribute ‘flags‘
改成如下: 报错原因:tensorflow1.x与2.x版本问题不兼容...

Android--Retrofit2执行多个请求任务并行,任务结束后执行统一输出结果
场景:后端上传文件接口只支持单个文件上传,而业务需求一次性上传多个图片,因此需要多个上传任务并发进行,拿到所有的返回结果后,才能进行下一个流程。 1、使用Java并发工具 private List<Response<JSONObject>…...

面试算法30:插入、删除和随机访问都是O(1)的容器
题目 设计一个数据结构,使如下3个操作的时间复杂度都是O(1)。 insert(value):如果数据集中不包含一个数值,则把它添加到数据集中。remove(value):如果数据集…...

Qt/C++开源作品45-CPU内存显示控件/和任务管理器一致
一、前言 在很多软件上,会在某个部位显示一个部件,专门显示当前的CPU使用率以及内存占用,方便用户判断当前程序或者当前环境中是否还有剩余的CPU和内存留给程序使用,在不用打开任务管理器或者资源查看器的时候直接得知当前系统的…...

win32汇编-使用子程序
当程序中相同功能的一段代码用得比较频繁时,可以将它分离出来写成一个子程序,在主程序中用call指令来调用它。这样可以不用重复写相同的代码, 仅仅用call指令就可以完成多次同样的工作了。Win 32汇编中的子程序也采用堆栈来传递参数ÿ…...

【论文阅读】 Cola-Dif; An explainable task-specific synthesis network
文章目录 CoLa-Diff: Conditional Latent Diffusion Model for Multi-modal MRI SynthesisAn Explainable Deep Framework: Towards Task-Specific Fusion for Multi-to-One MRI Synthesis CoLa-Diff: Conditional Latent Diffusion Model for Multi-modal MRI Synthesis 论文…...

ShareMouse for Mac(多台电脑鼠标键盘共享软件)
ShareMouse mac版是一款Mac平台上可以在多台电脑间共享鼠标的工具软件,sharemousefor Mac支持 Windows 与 Mac,并可以在不同电脑间共享剪贴板。只需要移动鼠标指针的到想控制的显示器那里去、鼠标光标就会神奇地“跨越”到邻近的电脑屏幕上。每个计算机都…...

中文编程开发语言工具开发案例:多种称重方式编程实际例子
中文编程开发语言工具开发案例:多种称重方式编程实际例子 上图为 计价秤,使用串口通讯线连接电脑的主机,软件自动读取称的重量,自动计算金额。这种方式称重快速,不需再打印条码。 上图这个称重方式为 一体称称重&#…...

国密sm2的Vue、Python、Java互通使用
目录 一、Vue 二、Python 三、Java 一、Vue # npm install --save sm-cryptoimport {sm2} from sm-crypto const cipherMode 1 const private_key d9d37f4f46e8514c6f9398a984e74f3eead994e8f4ac5f92e5deb313cb5ad6a6 const public_key 04 e332ee43ac37be458550652fb9…...

如何通过SK集成chatGPT实现DotNet项目工程化?
智能助手服务 以下案例将讲解如何实现天气插件 当前文档对应src/assistant/Chat.SemanticServer项目 首先我们介绍一下Chat.SemanticServer的技术架构 SemanticKernel 是什么? Semantic Kernel是一个SDK,它将OpenAI、Azure OpenAI和Hugging Face等大…...

DRM中render-node编号的分配
DRM系统 DRM是direct rendering manager的简称。DRM是linux kernel中与负责video cards功能的GPU打交道的子系统。DRM给出了一组API,可以供用户程序来发送命令和数据给GPU设备从而来控制比如display、render等功能。 render-node由来 在以前,DRM子系统…...

将输入对象转换为数组数组的维度大于等于1numpy.atleast_1d()
【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 将输入对象转换为数组 数组的维度大于等于1 numpy.atleast_1d() 选择题 使用numpy.atleast_1d()函数,下列正确的是? import numpy as np a1 1 a2 ((1,2,3),(4,5,6)) print("…...

js 删除树状图无用数据,如果子级没有数据则删除
有一个需求,当你从后端拿到一个树状图的时候,有些子级没数据,这时就需要我们处理一下数据,当然了,如果第一层底下的第二层没数据,第二层底下的所有都没数据,那这一层都不需要。 我的写法&#x…...

Docker 容器化(初学者的分享)
目录 一、什么是docker 二、docker的缺陷 三、简单的操作 一、首先配置一台虚拟机 二、安装Docker-CE 一、安装utils 二、 将 Docker 的软件源添加到 CentOS 的 yum 仓库中。这样可以通过 yum 命令来安装、更新和管理 Docker 相关的软件包。 三、将 download.docker.co…...

LCS 01.下载插件
题目来源: leetcode题目,网址:写文章-CSDN创作中心 解题思路: 假设需要 n 分钟下载插件,前 n-1 分钟将带宽加倍,最后一分钟下载时总时间最少。 解题代码: class Solution { public:int l…...

架构-设计原则
1、面向对象的SOLID 1.1 概述 SOLID是5个设计原则开头字母的缩写,其本身就有“稳定的”的意思,寓意是“遵从SOLID原则可以建立稳定、灵活、健壮的系统”。5个原则分别如下: Single Responsibility Principle(SRP)&am…...

在 Python 3 中释放 LightGBM 的力量:您的机器学习大师之路
机器学习是 Python 占据主导地位的领域,它一直在给全球各行各业带来革命性的变化。要在这个不断变化的环境中脱颖而出,掌握正确的工具是关键。LightGBM 就是这样一个工具,它是一个强大且快速的梯度提升框架。在这份综合指南中,我们将通过实际示例和示例数据集从基础知识到高…...

Spring学习笔记(2)
Spring学习笔记(2) 一、Spring配置非定义Bean1.1 DruidDataSource1.2、Connection1.3、Date1.4、SqlSessionFactory 二、Bean实例化的基本流程2.1 BeanDefinition2.2 单例池和流程总结 三、Spring的bean工厂后处理器3.1 bean工厂后处理器入门3.2、注册Be…...

cmd使用ssh连接Linux脚本
前言 在开发过程中,由于MobaXterm,我不知道怎么分页(不是屏内分页),用crtlTab,用起来不习惯,主要是MobaXterm连接了多个服务器,切换起来很麻烦。我是比较习惯使用altTab,…...

Python万圣节蝙蝠
目录 系列文章 前言 蝙蝠 程序设计 程序分析 运行结果 尾声 系列文章 序号文章目录直达链接1浪漫520表白代码https://want595.blog.csdn.net/article/details/1306668812满屏表白代码https://want595.blog.csdn.net/article/details/1297945183跳动的爱心https://want5…...

TCP流套接字编程
文章目录 前言TCP 和 UDP 的特点对比TcpEchoServer 服务端实现1. 创建 ServerSocket 类实现通信双方建立连接2. 取出建立的连接实现双方通信3. 服务端业务逻辑实现关闭资源服务端整体代码 TcpEchoClient 客户端实现1. 创建出 Socket 对象来与服务端实现通信2. 实现客户端的主要…...

Python迭代器创建与使用:从入门到精通
一、可迭代对象 1、 什么是可迭代对象? 表示可以逐一迭代或者遍历的对象,序列:列表、元组、集合、字符串。非序列:字典、文件。自定义对象:实现了__iter__()方法的对象;实现了使用整数索引的 getitem()方…...

mac虚拟机安装homebrew时的问题
安装了mac虚拟机,结果在需要通过“brew install svn”安装svn时,才注意到没有下载安装homebrew。 于是便想着先安装homebrew,网上查的教程大多是通过类似以下命令 “ruby <(curl -fsSkL raw.github.com/mxcl/homebrew/go)” 但是都会出现…...

学信息系统项目管理师第4版系列32_信息技术发展
1. 大型信息系统 1.1. 大型信息系统是指以信息技术和通信技术为支撑,规模庞大,分布广阔,采用多级 网络结构,跨越多个安全域;处理海量的,复杂且形式多样的数据,提供多种类型应用 的大系统 1.1.…...

Vue3 + Nodejs 实战 ,文件上传项目--大文件分片上传+断点续传
目录 1.大文件上传的场景 2.前端实现 2.1 对文件进行分片 2.2 生成hash值(唯一标识) 2.3 发送上传文件请求 3.后端实现 3.1 接收分片数据临时存储 3.2 合并分片 4.完成段点续传 4.1修改后端 4.2 修改前端 5.测试 博客主页:専心_前端…...

宏(预编译)详解
目录 一、程序的编译环境 二、运行环境 三、预编译详解 3.1预定义符号 3.2.1 #define 定义标识符 3.2.2 #define 定义宏 3.2.3#define替换规则 3.2.4 #和## 2)##的作用: 3.2.5宏和函数的对比 3.2.6宏的命名约定和#undef指令 一、命名约定: …...