【小黑嵌入式系统第六课】嵌入式系统软件设计基础——C语言简述、程序涉及规范、多任务程序设计、状态机建模(FSM)、模块化设计、事件触发、时间触发

news2024/11/27 15:32:45

上一课:
【小黑嵌入式系统第五课】嵌入式系统开发流程——开发工具、交叉开发环境、开发过程(生成&调试&测试)、发展趋势

文章目录

    • 一 单片机的C语言简述
      • 1、为什么要用C语言?
      • 2、单片机的C语言怎么学?
        • 之一:变量定义
        • 之二:特殊寄存器操作
        • 之三:位操作
        • 之四:中断
        • 之五:内部函数(intrinsic Function)
        • 之六:函数的可重入性
        • 讨论与总结:
    • 二 程序设计规范
      • 1、什么要学习程序设计规范?
      • 2、程序规范的基本原则?
        • (一)编程风格
        • (二)可移植性
        • (三)版本管理、可配置
    • 三 前后台多任务程序设计
      • (一)前后台程序的基本概念
      • (二)前后台程序的编写基本原则
        • (1)任何一个任务都不能阻塞CPU。
        • (2)关注函数重入问题
        • (3)临界代码保护(Critical Code Protection)
        • (4)临界代码的保护方法
      • 讨论与总结
    • 四 FSM:状态机建模
      • 1、什么是状态机?
      • 2、为什么要引入状态机?
      • 3、流程图无法描述的软件行为举例
      • 4、引入“状态机” 的优势
      • 5、状态机的表示方法:状态转移图
      • 6、由状态转移图生成代码
      • 7、状态机建模举例
    • 五 模块化程序设计
      • 1、模块化程序的原则
      • 2、键盘模块化程序
      • 3、带长短键识别的键盘模块化程序
      • 4、串口收发模块化程序
      • 5、数码管显示模块化程序
      • 6、时钟和日历程序
    • 六 事件触发多任务程序设计
      • 1、什么是事件触发程序?
      • 2、事件触发程序的程序架构
      • 3、事件触发程序设计范例
    • 七 时间触发系统


一 单片机的C语言简述

1、为什么要用C语言?

理由1:大幅减少编程劳动量

在这里插入图片描述
理由2:代码的通用性

在这里插入图片描述

  • C语言可以为世界上任何一款处理器编程 (包括所有单片机)
  • 在任何一款单片机上开发的程序,都可以移植到别的处理器上。
  • 代码的模块化、可复用性 => 减少重复劳动、加快开发速度。

2、单片机的C语言怎么学?

在这里插入图片描述
PSoC Creator集成开发环境所配备的PSoC 5LP编译器为GCC-ARM(GNU Compiler Collection for ARM Embedded Processors),是一款免费的C/C++编译器。其文档位于图中gcc目录内。
C预处理器、链接器、汇编器、调试器、函数库等相关软件工具的文档位于图中的pdf目录及其子目录内。

之一:变量定义

在这里插入图片描述

处理器、编译器类型的不同,在变量定义上与VC略有不同。

几个特殊关键词的含义:
 
const:定义常量。const关键字定义的常量被放在ROM中,常用于定义如系数表、显示段码表等。
static :相当于本地全局变量,在函数内使用,可以避免全局变量使用混乱。
volatile :定义“挥发性”变量。编译器将认为该变量的值会随时改变,对该变量的任何操作都不会被优化掉。

之二:特殊寄存器操作

在这里插入图片描述
结论:

(1)特殊寄存器经过定义之后,可以像变量一样操作。

(2)包含单片机头文件,就已经完成了变量定义工作。

之三:位操作

在这里插入图片描述
结论:若处理器不支持单个位的操作,则要用左边的方式实现。

之四:中断

在这里插入图片描述
结论:(1)C语言将中断作为特殊函数 (2)该函数由中断机制调用

之五:内部函数(intrinsic Function)

在这里插入图片描述
结论:
(1)内部函数是将该款单片机的一些特殊指令做成函数形式
(2)在使用前,要包含内部函数头文件。

之六:函数的可重入性

在这里插入图片描述
结论:
(1)低端单片机因资源少,函数用静态传递,不可重入。
(2)中高端单片机编译器,函数用栈传递,允许重入。

讨论与总结:

1、即使是初学者,也完全可以在不深入了解汇编指令系统的情况下直接开始C语言开发

2、任何一款处理器的C语言,都是在标准C语言 (ANSI-C) 上增加对相应处理器的特殊操作而构成。

3、C编译器的表现通常非常优秀。如果没有几年的手工汇编经验3很难写出比C编译器更高效的代码。
4、如果在编程过程中将硬件差异集中到某个很小的局部,整个程序通过很简单的修改就能编译成另一CPU的机器码。这就是所谓的“代码移植”,是嵌入式软件设计最重要的思想之一。
5、在一开始就树立可移植性、模块化的概念,养成好的编程习惯,这正是下一部分对减少重复劳动、加快开发速度有很大帮助的主要目的。

二 程序设计规范

1、什么要学习程序设计规范?

1、程序不仅要被计算机执行,还要给程序员阅读,以及被今后重复使用。
2、一个风格清爽而严谨、规范化的程序更容易被读懂,更容易被修改、排错和移植。
3、规范化编程、高度一致的风格和正确的习惯还有助于保持思维清晰,写出正确无误的代码。特别是一个开发团队共同工作时,规范一致化的编程尤其重要
4、每个初学者在项目初期都会因为不良编程习惯浪费大量时间,因此若能在开始写程序时就重视规范化问题,对顺利渡过提高阶段有很大帮助。

2、程序规范的基本原则?

原则:

(1)一致的代码风格,统一的变量名、函数名命名规则

(2)符合英语语法、可阅读的代码

(3)关键代码100%注释

(4)硬件有关、硬件无关代码分离,可移植性强

(5)每个对象都具有完善的封装,接口形式简洁、易用

(6)对所有资源严格要求硬件隔离层,软件中不允许直接访问硬件,不允许跨层调用。

(一)编程风格

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(二)可移植性

1)消除CPU差异

若希望自己写的程序在不同处理器上运行,首先需要了解这些处理器的不同之处。其中包括硬件的不同以及特殊语法的差异。例如MSP430单片机没有位操作指令,8051单片机有,若两者之间程序需相互移植,首先需要消灭这个差异。
在这里插入图片描述
2)消除硬件差异

在这里插入图片描述
在这里插入图片描述

更改数码管硬件布线,无需重写段码表

3)封装

封装是指将软/硬件对象的属性与行为绑定在一起,并放置在一个模块单元内。该单元负责将所描述的属性隐藏起来,外界对其内部属性的所有访问只能通过提供的应用程序接口实现。

在这里插入图片描述

初学者常见问题:

在这里插入图片描述
4)应用程序接口(API)

接口是对软/硬件对象的抽象,对外提供的服务和访问功能,

即:对象封装后对外呈现成什么样?

原则:(1)使用方便(2)功能丰富(3)但不要过多过滥

【例】为液晶显示模块规划应用程序接口:

在这里插入图片描述
5)软件层次

例:菜单程序
在这里插入图片描述
 
(1)杜绝跨层调用
(2)功能模块可以任意拼接、组合
(3)要有硬件隔离层(HAL)
(4)更换任意层代码,上下层建筑不变

(三)版本管理、可配置

在这里插入图片描述
 
(1)尽可能减少软件副本
(2)类似的产品/设计尽可能公用同一代码
(3)利用宏定义配置功能
(4)永远在最新的代码上开发,保留最新版

三 前后台多任务程序设计

(一)前后台程序的基本概念

在这里插入图片描述
任务(Task) :指完成某一单一功能的程序
后台程序:对时间要求不严格的任务,通常在主循环内执行
前台程序:要求快速响应或者时间严格的任务,通常中断内
队列/缓冲:用于暂存后台来不及处理的前台事件

(二)前后台程序的编写基本原则

(1)任何一个任务都不能阻塞CPU。

每个任务都应主动结束,让出CPU。不能有等待、死循环、长延时等环节(对初学者来说是难点!

在这里插入图片描述

(2)关注函数重入问题

可重入(Reentrancy):函数在自己调用自己的时候,不必担心数据被破坏。

从软件工程角度对函数可重入的作用可以解释为:具有可重入性的函数能够被多个任务同时调用。在后台程序中,任务都是顺序执行的,不存在多个任务同时调用一个函数的情况。但可能出现前台中断服务程序与后台任务同时调用某个函数。

因此对于前后台公用函数,必须是可重入的

【例】:

在这里插入图片描述

(3)临界代码保护(Critical Code Protection)

临界代码:运行时不可分割的代码,这部分代码不允许被中断打断

1) 依靠软件产生时间严格时序的程序段。

/***************************************************
*名称:          Pulse 10us()
*功能:         产生10us脉冲
*入门参数:     无
**************************************************/
void Pulse_10us()
{
	_DINT();            // -------以下是临界代码区,不允许被中断
	IO=1;               // 置高
	_delay_cycles(8); 	// 高电平持续10us (O赋值身耗2us)
	IO=0;               //置低
	_EINTO0;            // -------以上是临界代码区-----------
}

2)共享资源互斥性造成的临界代码

程序中任何可被占用的实体都称为“资源”。资源可以是硬件设备,如定时器、串口、打印机、键盘、LCD显示器等,也可以是变量、数组、队列、等数据。

被一个以上任务所占用的资源叫做“共享资源”。共享资源若不能同时被多任务占用,则具有“互斥性”(Mutual Exclusive)。

【例】:前后台同时调用液晶显示函数造成花屏

在这里插入图片描述

(4)临界代码的保护方法
  • 关中断、开中断
    隐患: 如果在A函数的临界代码区调用了另一个函数B,B函数内也有临界代码区,从B函数返回时,中断被打开了,这将造成A函数后续代码失去临界保护。所以,使用该方法时,不能在临界代码区调用任何具其他有临界代码的函数!
  • 利用硬件栈保存中断使能状态
    优点:不影响函数调用
    缺点:很多单片机的C语言不支持操作硬件栈
  • 利用变量保存中断使能状态
    缺点:每一段临界代码要消耗2-4字节内存
  • 利用模拟栈保存中断使能状态
    缺点:速度慢

典型错误1:在临界代码区调用其他临界代码

A()
{	
	int_Disable();	
	B();	// 这期间中断是开的,所执行的代码不被临界保护
	int_Enable();
}


B()
{
	int_Disable();	
	// ...
	int_Enable();
}

典型错误2:在主函数和中断中都调用LCD操作函数

  • LCD操作耗时长,不应放在中断中。
  • LCD操作是临界代码,LCD是互斥性共享资源,LCD操作函数都是不可重入的,如果主函数里没有做临界代码保护,结果就是没多久屏幕就花了或呈死机效果。

讨论与总结

  1. 后台中任务顺序执行。每个后台任务中的内存(局部变量)在任务结束后可以全部释放,让给下一个任务使用。即使在RAM很少的处理器上也能同时执行众多任务。
  2. 后台中任务顺序执行。天然避免了后台任务资源互斥问题,但仍需考虑前后台之间的资源互斥问题。
  3. 前后台程序的结构灵活,实现形式与实现手段多样,是使用最广的程序结构,但缺乏架构标准,维护、升级、排错都很困难。
  4. 必须要程序员自己来判断和处理临界代码的隐患。
  5. 程序多任务的执行依靠每个任务的非阻塞性来保证,是编程最大的难点,下一节将介绍的FSM将是解决这一问题的利器!

四 FSM:状态机建模

在这里插入图片描述

1、什么是状态机?

有限状态自动机(Finite-State Machine, FSM),简称状态机,是表示有限个状态以及在这些状态之间的转移动作等行为的数学模型。

2、为什么要引入状态机?

流程图的缺陷:

1、不能用于描述“任何时候”发生的事件
2、无法描述“由外部事件决定流程”的程序
3、不适合描述带有阻塞的并发过程
4、难以描述大量的独立事件。

需要:能够描述并发结构的软件,能从行为的角度来描述软件,且能够根据模型生成代码,也能够对软件进行完整测试的新手段—状态机模型。

3、流程图无法描述的软件行为举例

(1)不能用于描述“任何时候”发生的事件
在这里插入图片描述
(2)不能用于描述由外部事件决定流程的事件

【例】:电子表有两个按键,但按键顺序完全由外部决定
在这里插入图片描述
(3)不适合描述带有阻塞的并发过程

【例】:一个单片机同时控制2台电动机完成运转时序

在这里插入图片描述
(4)不适合描述大量的独立事件

【例】:投币式自动咖啡机程序

流程图:投币->选咖啡->出咖啡->结束
然 而…

  • 如果没有放咖啡杯就选择咖啡,会发生什么情况?

  • 如果咖啡杯未满之前,用户取走了咖啡杯,会发生什么情况?

  • 如果咖啡灌了一半时,用户取走咖啡杯,再放回,能否把剩下一半继续加满?

  • 如果咖啡灌了一半时,用户取走咖啡杯,不再放回,剩下一半是否会加到下一用户杯中?

  • 如果咖啡杯未满之前,用户取走了咖啡杯,然后按退币扭,该如何处理?

  • 如果还没有完成一次点单之前,用户再次投币,会发生什么情况?

  • 如果一杯咖啡尚未加满时,用户又点了另一种咖啡,会发生什么情况?

  • 如果用户一次投入两杯咖啡的钱,该怎样处理?

  • 如果咖啡存储容器已空,用户点单时能否正确提示?

  • 如果咖啡杯未满之前,咖啡机空了,能否给用户退款?

4、引入“状态机” 的优势

上面这些例子中,软件下一步要执行的功能不仅与外界入信息有关,还与系统的“当前状态”有关。状态机就是一种基于“状态”与“事件”的软件描述手段!其优势在于:

(1) 能够处理并发。由于系统在每一时刻只能有唯一的状态,在每一个状态下,可能发生的事件也是有限的。因此系统中即使存在有大量的独立事件,软件描述也会简单得多。

(2) 能够消除阻寒。真正需要CPU处理的只有系统状态发生改变的那一刻,在系统等待事件到来的期间,是不需要CPU处理的。如果能够用状态与事件的形式来描述软件,能够将CPU从等待事件发生的过程中解放出来,从而生成无阻塞的代码。

(3) 能够降低系统的复杂度,提高可测性

5、状态机的表示方法:状态转移图

在这里插入图片描述

圆圈:状态 (有限个)
有向箭头:状态转移
Event事件:事件发生时将触发状态转移
Action动作:状态转移的同时执行动作

6、由状态转移图生成代码

方法1、在状态中判断事件(事件查询)

在这里插入图片描述

switch(State)		//根据当前状态决定程序分支
{
	case S0:			//在s0状态
		if(Event0)
		{			//如果查询到Event0事件
					Action0();
		}
		else if(Event1)
		{			//如果查询到Event1事件
					Action1();
					State=S1;
		}
		else if(Event2)
		{			//如果查询到Event2事件
					Action3();
					State=S2;
		}
		break;
	case S1:			//在s1状态
		if(Event2)
		{			//如果查询到Event2事件
					Action2();
					State=S2;
		}
		break;
......

方法2、在事件中判断状态(事件触发)

在这里插入图片描述

7、状态机建模举例

例1 电子表程序

在这里插入图片描述

====A键中断====
switch(Status)		/*根据当前状态处理A键所引发的状态跳跳转*/
{
	case DISP_TIMME: Status = DISP_DATE;break://时间显示时按A键,显示日期
	case DISP_DATE: Status = DISP_SEC; break;
	case DISP_SEC: Status= DISP_TIME; break;
	case SET_HOUR: if(++Hour>23) Hour=0; break; //小时设置时按A键调整小时case SET_MINUTE: if(++Min>59) Min=0; break;
	case SET_MONTH: if(++Month>12) Month=1; break;
	case SET_DATE: if(++Date>31) Date=0; break;
}

====B键中断=====
switch (Status)			/*/根据当前状态处理B键所引发的状态跳转/*/
{
case DISP_TIME;		Status= SET_HOUR; break;	//时间显示时按B键,设置小时
case DISP_DATH;		Status= SET_HOUR: break;	//日期显示时按B键,设置小时
case DISP_SEC;		Second 0; break;			//秒钟显示时按B键,秒归零
case SET_HOUR;		Status= SET_MINUTE; break;	//小时设置时按B键,分钟设置
case SET_MINUTE;	Status= SET_MONTH; break;	//分钟设置时按B键月设置
case SET_MONTH;		Status= SET_DATE; break;	//月设置时按B键,日设置
case SET_DATE;		Status= DISP_TIME; break;	//日设置时按B键,显示时间
}

例2 长短按键识别

在这里插入图片描述
例3 事件序列匹配

在这里插入图片描述

五 模块化程序设计

1、模块化程序的原则

  1. 非阻寒性 不能长时间占用CPU,更不死等待某个事件的发生,尽快地让出CPU,供后续任务执行。
  2. 硬件隔离 屏蔽硬件特征,起到硬件隔离层的作用。上层软件将不涉及直接硬件操作。
  3. 模块独立性 各个程序库之间没有代码关联性(没有互相调用和隶属关系),在使用时,各个模块文件可以任意拼接、组合、拆分。
  4. 时间独立性 使用缓冲区、事件队列等手段,对时间关联性强的事件进行斩存和缓冲,使之可以被异步处理。
  5. 可移植性 代码都按照标准C的规范,很容易的移植到其他处理器上,或者其它硬件平台上。
  6. 100%注释 注释关键代码的功能或设计意图,以及每个函数的功能.入口出口参数、说明及注意事项,使用范例等。
  7. 开放性 方便日后修改、添加新的功能函数。

2、键盘模块化程序

在这里插入图片描述

3、带长短键识别的键盘模块化程序

在这里插入图片描述

4、串口收发模块化程序

在这里插入图片描述

5、数码管显示模块化程序

在这里插入图片描述

6、时钟和日历程序

在这里插入图片描述

六 事件触发多任务程序设计

1、什么是事件触发程序?

在这里插入图片描述
任务全部在中断内完成,主程序休眠。
可以看做前后台程序中,只有前台任务。

特点:1)实时性较好,事件响应较快;2)低功耗

2、事件触发程序的程序架构

在这里插入图片描述

中断:获取原始的事件信息。
事件引擎:判断何种事件发生,并调用相应处理程序。
(一个中断有多个中断源时)
事件处理程序:只负责某个事件的处理,要求非阻塞。

3、事件触发程序设计范例

有3个按键 (S1、S2、S3),按下为低电平。外部输入电压从ADC输入。设计一款超低功耗的电压表,要求用事件触发结构实现下列功能:

  1. 实现电压测量功能,每秒刷新显示2次电压测量值。
    每次测量值由ADC连续采样4次求平均得到。
  2. 按下S1键时,斩停采样与显示刷新(保持功能)
  3. 按下S2键时,恢复采样与刷新。
  4. 按下S3键时,将采样数据从串口发出。

在这里插入图片描述
在这里插入图片描述
第3步:编写5个事件处理程序,此时并不关心事件如何发生如何被检测到,以及按什么顺序发生

第4步:测试。按照预先设定的顺序,依次调用5个事件处理程序(并不需要硬件上真的发生事件),模拟事件发生,即可进行代码测试。

第5步:编写事件引擎,在中断内检测和判判断事件,并分别调用相应的事件处理程序。

七 时间触发系统

时间触发系统可以理解为一种特殊的事件触发系统,但它另有自己的特点。

例子:一个医生,必须在一些护理人员的帮助下,通宵照顾十个危重病人,方案可以是

● 安排护理人员在某个病人出现严重问题时唤醒他
——事件触发
● 每小时闹铃,闹铃响时起床去探访每个病人
——时间触发

以每小时的间隔探访病人,医生能在严重并发症出现之前探访每个病人并安排合理的治疗。另外,工作量在整个晚上平摊。于是,所有病人都能平安地度过这个夜晚。

而前一种方式可能会出现护理人员在唤醒医生时,有多个病人都出现了严重并发症,需要依次做手术,后面的病人有可能来不及得到手术治疗。

这个医院的例子在事件驱动的系统中,即可能同时发生几个事件。需要处理同时发生的多个事件不但增加了系统复杂性,而且降低了对事件触发系统在所有情况下的行为做出预计的能力。

相比而言,在时间触发的嵌入式系统中,设计人员能够通过仔细安排可控的顺序,保证一次只处理一个事件。

许多嵌入式系统并不需要睡眠,采用时间触发方法有很多好处,有助于改善可靠性和安全性(如广泛应用于航空航天工业和汽车工业),主要原因在于系统的行为可以预计。

时间触发方法还能降低CPU的负荷,并减少存储器的使用量。

嵌入式系统需要执行的任务分为两种:

  ● **周期性任务**,比如每100ms执行一次
  ● **单次任务**,如在50ms的延迟后执行一次

考虑方案1:

void main(void)
{
    Init_System();
    while(1)
    {
        X();                     // 执行任务(耗时10ms)
        Delay_90ms();   // 延迟90ms
    }
}

需要知道任务X的精确运行时间

这个运行时间永不变化—— 不可行

考虑方案2:

基于定时器中断,在一定的时刻调用函数

如果要支持多个任务(这些任务一般具有不同的运行时间并以不同的时间间隔运行),可以每个任务都使用一个定时器。

但:浪费硬件资源(或者不够用)、硬件的维护增加、会同时产生多个定时器中断。——不合理

解决方案:使用调度器

● 调度器可以看作是一个简单的操作系统,允许以周期性或单次方式来调用任务。

● 从底层的角度来看,调度器可以看作是一个由许多不同任务共享的定时器中断服务程序。

用调度器来调度三个任务的执行:

void main(void)
{
    SCH_Init();     // 设置调度器一次

    /*---- 增加各任务至任务队列(时间分辨率为1ms)----*/
    // Function_A将每隔2ms运行一次
    SCH_Add_Task(Function_A, 0, 2);
    // Function_B将每隔10ms运行一次
    SCH_Add_Task(Function_B, 1, 10); 
    // Function_C将每隔15ms运行一次
    SCH_Add_Task(Function_C, 3, 15); 

    SCH_Start();   // 启动调度
    while(1)
    {
       // 按调度算法执行任务队列中各任务
       SCH_Dispatch_Tasks();   
    }
}

在这里插入图片描述
调度器的分类

  ● 合作式调度器
  ● 抢占式调度器

合作式调度器:
● 任务在特定的时刻被调度运行(以周期性或单次方式)

● 当任务需要运行时,被添加到等待队列

● 当CPU空闲时,运行等待任务中的下一个(如果有的话)

● 前一任务运行直到完成,才轮到下一个等待任务

● 简单,用少量代码即可实现

● 一次只为一个任务分配存储器

● 通常完全由高级语言如C实现

● 小心设计可以实现快速响应外部事件

● 简单、可预测、可靠并且安全

抢占式调度器:

● 任务在特定的时刻被调度运行(以周期性或单次方式)

● 当任务需要运行时,被添加到等待队列

● 等待的任务运行一段固定的时间,如果没有完成,将被暂停并放回到等待队列。然后下一个等待任务(如果有的话)将运行一段固定的时间。

● 高优先级的任务可以抢占低优先级任务优先运行

● 复杂,“并行处理的”任务试图访问公用资源时需避免冲突等

● 必须为被抢占任务的所有中间状态分配存储器

● 通常(至少是部分)由汇编语言编写

● 对外部事件响应快

● 与合作式调度比,通常认为其更不可预测、并且可靠性较低

混合式调度器:

● 支持多个合作式调度的任务

● 支持一个抢占式任务(可以“中断”合作式任务)

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

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

相关文章

高并发和存储之间的关系是什么?

文章目录 🔊博主介绍🤖博主的简介📥博主的目标 🥤本文内容🍊 一、高并发对存储的压力🍊 二、存储的性能和可扩展性 📢总结 🔊博主介绍 📕我是廖志伟,一名Java…

【JAVA学习笔记】53 - 集合-List类及其子类Collection、ArrayList、LinkedList类

项目代码 https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter14/src/com/yinhai/collection_ https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter14/src/com/yinhai/list_ 集合 一、集合引入 前面我们保存多个数据使用的是数组…

thinkphp链接mqtt服务器,然后在订阅下发布消息

cmd打开项目根目录&#xff0c;安装插件&#xff0c;执行下面的命令 composer require php-mqtt/client执行完成之后会在vendor 目录下有php-mqtt 文件 然后在你的 extend文件下 新建mqtt文件 在文件中新建 Mqtt.php 下面是代码 <?php /** S: * Name: 控制器: * Autho…

金蝶云星空创建自动下推并保存公共服务

文章目录 金蝶云星空创建自动下推并保存公共服务创建公共方法按单下推数据按明细行下推数据调用下推操作 调用公共方法 金蝶云星空创建自动下推并保存公共服务 创建公共方法 按单下推数据 /// <summary>/// 获取单据转换数据包/// </summary>public DynamicObjec…

“证意联盟”聊聊亚马逊云科技认证的价值和意义(文末有福利)

云职场“卷”人都在干嘛&#xff1f;通勤途中刷刷线上课程&#xff0c;每天提升一点云技能&#xff1b;周末时间做做官方题库&#xff0c;每周增加一点考试通过的概率&#xff1b;月底试试模拟考&#xff0c;每月加强一点信心&#xff1b;年末准备充分考取亚马逊云科技认证&…

Java获取指定时间一周至周日的日期

Java获取指定时间一周至周日的日期&#xff1a; /*** 获取指定时间 当前周的周一至周日的时间* return*/public static List<String> getWeekData(Date dataTime){/*** 转为calendar格式* calendar.get(Calendar.MONTH)1 calendar中的月份以0开头* Calendar.DAY_OF_WEE…

5分钟带你认识web自动化测试

1.什么是自动化测试&#xff1f; 自动化测试的概念: 软件自动化测试就是通过测试工具或者其他手段&#xff0c;按照测试人员的预定计划对软件产品进行自动化测试&#xff0c;他是软件测试的一个重要组成部分&#xff0c;能够完成许多手工测试无法完成或者难以实现的测试工作&a…

【3ds max】给指定的面设置材质

1. 首先将物体转换为可编辑多边形 2. 选中需要赋予材质的面 按m键弹出材质编辑器 点击“将材质指定给选定对象”

4.1 Bloom算法

一、Bloom算法介绍 1.具体效果 2.实现思路 先将原图按照一定阈值提取较亮的区域模糊提取出的图像将模糊过的图像与原图混合 3.HDR与LDR LDR&#xff08;Low Dynamic Range&#xff0c;低动态范围&#xff09; JPG、PNG格式图片RGB范围在[0,1]之间 HDR&#xff08;High Dynam…

SpringCloud(四) Nacos注册中心

目录 一, Nacos 1.1 Nacos的安装 1.2 服务注册到Nacos 1, 引入依赖 2, 配置Nacos地址 3, 重启 4, 进行访问 二, 服务分级存储模型 2.1 分级模型 2.2 Nacos的集群配置 1, 给user-service配置集群 2, 同集群优先的负载均衡 2.3 权重配置 国内公司一般都推崇阿里巴巴…

【嵌入式】HC32F07X CAN通讯配置和使用

目录 一 背景说明 二 原理分析 三 CAN通讯硬件设计 四 CAN通讯软件配置 五 CAN通讯测试 一 背景说明 使用小华&#xff08;华大&#xff09;的MCU HC32F07X实现 CAN 通讯配置和使用 二 原理分析 【1】CAN原理说明&#xff08;参考文章《CAN通信详解》&#xff09;&#x…

使用 puppeteer 库采集豆瓣音频简单代码示例

今天要给大家分享的采集代码&#xff0c;主要是使用 puppeteer 库进行编写的&#xff0c;用于采集豆瓣网相关音频。这段代码也是非常的简单实用&#xff0c;一起来看看吧。 // 引入 puppeteer 库 const puppeteer require(puppeteer);// 定义获取代理服务器的函数 function …

针灸养生服务预约小程序的效果如何

针灸服务的市场需求度很高&#xff0c;每个城市中都有不少相关品牌&#xff0c;对商家来说&#xff0c;如何引流拓客、打造品牌是生意开展的首要条件之一&#xff0c;且主要以同城用户为主&#xff0c;或连锁情况下为各店引流&#xff0c;但传统线下模式很难实现生意拓展。 那…

蓝桥杯每日一题2023.10.31

题目描述 全球变暖 - 蓝桥云课 (lanqiao.cn) 题目分析 果然有关连通块类的问题使用dfs都较为好写~~ 我们可以通过判断连通块的代码来加上部分条件算出被完全淹没的岛屿个数 在岛屿中如果有为"#"的a[i][j]上下左右全部是"#"则说明此岛屿一定不会被完全…

2023年【低压电工】找解析及低压电工模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 低压电工找解析是安全生产模拟考试一点通生成的&#xff0c;低压电工证模拟考试题库是根据低压电工最新版教材汇编出低压电工仿真模拟考试。2023年【低压电工】找解析及低压电工模拟考试 1、【单选题】()仪表可直接用…

VIVO应用商店评论数据抓取

VIVO应用商店的app评论数据抓取 每个应用的评论能获取到最新的 100页 数据 每页20条&#xff0c;也就是 2000条评论数据 接口&#xff1a; pl.appstore.vivo.com.cn/port/comments/ 爬取运行截图&#xff1a;

嵌入式应用选择正确的系统设计方法:第二部分

在设计嵌入式系统之前&#xff0c;我们需要知道我们在设计什么。在这种情况下&#xff0c;术语“要求”和“规范”以多种方式使用-有些人将它们用作同义词&#xff0c;而另一些人将它们用作不同的阶段。它们在这里用来表示设计过程中相关但截然不同的步骤。 需求 是对客户需求…

Leaflet地图工具

2023 年 5 月 18 日 — Leaflet 1.9.4 正式发布! Leaflet 是一个开源并且对移动端友好的交互式地图 JavaScript 库。 它大小仅仅只有 42 KB of JS, 并且拥有绝大部分开发者所需要的所有地图特性 。 Leaflet 简单、高效并且易用。 它可以高效的运行在桌面和移动平台, 拥有着大…

[Machine Learning][Part 7]神经网络的基本组成结构

这里我们将探索神经元/单元和层的内部工作原理。特别是,与之前学习的回归/线性模型和逻辑模型进行比较。最后接介绍tensorflow以及如何利用tensorflow来实现这些模型。 神经网络和大脑的神经元工作原理类似&#xff0c;但是比大脑的工作原理要简单的多。大脑中神经元的工作原理…

Ajax学习笔记第6天--COOKIE

放弃该放弃的是无奈&#xff0c;放弃不该放弃的是无能&#xff0c;不放弃该放弃的是无知&#xff0c;不放弃不该放弃的是执着&#xff01; 【1. cookie】 1.Cookie机制 而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕&#xff0c;客户端与…