基于PID的单片机温度控制系统设计

基于PID的温度控制系统设计

摘要

温度是工业上最基本的参数,与人们的生活紧密相关,实时测量温度在工业生产中越来越受到重视,离不开温度测量所带来的好处,因此研究控制和测量温度具有及其重要的意义。

本设计介绍了以AT89C52单片机为主控器件,基于PID的温度控制系统的设计方案和设计的基本原理。由DS18B20收集温度信号,并以数字信号的方式送给单片机进行处理,从而达到温度控制的目标。主要包括硬件电路的设计和系统程序的设计。硬件电路由主控器件、温测电路、温控电路和显示电路等组成。软件设计部分包括:显示电路、温度信号处理,超温警报、继电器控制、按键处理等程序。


目录

摘  要

Abstract

1绪论

1.1课题的来源

1.2课题的意义

1.3课题研究的主要内容

2硬件设计

2.1单片机控制模块的设计

2.1.1 AT89C52单片机简介

2.1.2 单片机的引脚功能

2.1.3 单片机控制模块的电路设计

2.1.4 电源设计

2.2温度采集模块的设计

2.2.1 DS18B20芯片的简介

2.2.2 DS18B20的内部结构

2.2.3 DS18B20的供电方式

2.2.4 DS18B20的引脚功能

2.3温度控制模块的设计

2.4按键及显示模块的设计

2.4.1 LCD1602的参数和引脚功能

2.4.2 LCD1602的特点

2.4.3 按键电路的设计

2.5报警模块的设计

3软件设计

3.1主程序的设计

3.2DS18B20读温度程序的设计

3.3键盘扫描程序的设计

3.4报警处理程序的设计

3.5PID控制算法

4系统仿真

参考文献

致谢

附录

1


 

基于PID的温度控制系统设计

1绪论1.1课题的来源

在食品加工、化工、冶炼等工业控制和生产中,在工业生产和日常生活中经常要用到温度检测和控制。以及各种各样的加热炉、热处理器等,都对温度有着严格的要求。传统的测温元件有热电偶和热电阻。而热电偶和热电阻测出的通常是电压,再转换成相应的温度值,在硬件方面是个难点,而且从设计和调试的角度来讲都是很复杂的,以及高昂的制作成本。但采用DS18B20作为温测元件,然后用单片机对温度进行控制,可以大幅度提高温度控制的技术指标,而且还具有控制方便、简单、灵活等特点。单片机已经渗透到我们生活的各领域,仪表仪器、家用电器、航空航天、计算机通讯网络和数据的传输,包括工业自动化的实时控制和数据处理等,这些都离不开单片机。用单片机可构成丰富多样的数据采集系统和控制系统。像工厂流水线智能化的管理、电梯智能化的控制、多种报警系统,都可以与计算机联网构成二级控制系统等。

1.2课题的意义

温度传感器是测量温度的关键,现在温度传感器正由模拟式向数字式、集成化向智能化、网络化的方向发展。在测量温度的电路中,使用热敏电阻之类的器件利用其感温效应,将随被测温度变化的电压或电流采集过来,先进行A/D转换,然后用单片机进行数据的处理,再在显示电路上,将被测温度显示出来。这种设计需要用到A/D转换电路,因此电路的设计比较复杂。
继而想到可以采用智能温度传感器来设计数字温度计。本数字温度计的设计采用美国半导体公司DALLAS推出的一种改进型智能温度传感器DS18B20作为检测元件,其温度值可以直接被读出来,通过单片机AT89C52的读写和显示,然后用LCD1602来进行显示。它的测温范围为-55℃~+125℃,最大分辨率可达0.0625℃。而且采用3线制与单片机相连,减少了外部的硬件电路,具有低成本和易使用的特点。

1.3课题研究的主要内容

1、总体设计的内容
总体设计的主要内容有:利用单片机作为系统的主控制器,利用DS18B20作为温度传感器,将信号送入单片机进行处理,经过PID算法后,单片机的输出用来控制加热棒的输出功率,从而实现对温度的控制。
2、总体设计的基本要求
总体布置的基本要求主要有:
(1)温度控制系统的总体设计和思路;
(2)各部分原理说明;
(3)温度控制系统硬件设计,有理论依据,有分析计算过程,主要元件有原理和说明,所有元件必须要有型号和参数;
(4)温度控制系统软件设计,可以使用汇编语言或C语言编程。主要软件必须能在设计好的硬件电路上正确运行。


2硬件设计

硬件设计方框图如图2-1所示,它主要由五个模块组成:
  • 单片机控制模块;
  • 温度采集模块;
  • 温度控制模块;
  • 按键及显示模块;
  • 报警模块。

图2-1 硬件设计方框图

2.1单片机控制模块的设计

方案一:
采用8031芯片,其内部没有程序存储器,需要进行外部扩展,这给电路增加了复杂度。
方案二:
采用2051芯片,其内部有2KB单元的程序存储器,不需外部扩展程序存储器。但由于系统用到较多的I/O口,因此此芯片资源不够用。
方案三:
采用AT89C52单片机,其内部有4KB单元的程序存储器,不需外部扩展程序存储器,而且它的I/O口也足够本次设计的要求。
方案评价:
比较这三种方案,综合考虑单片机的各部分资源,本次设计选用方案三。

2.1.1 AT89C52单片机简介

AT89C52是ATMEL公司生产的51系列单片机。片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度,兼容51指令系统,Flash存储单元和8位中央处理器置于片内,AT89C52单片机功能强大,在许多复杂的应用场合都可以用到。
单片机是微型机的一个分支,单片机的最大特点就是在超大规模的集成电路芯片上集成了定时器、存储器、CPU、和多种输入/输出接口电路。由于单片机的这种结构,相应的它具有很多的特点。
它的特点包括:
  • 可靠性高;
  • 抗干扰能力强;
  • 控制能力强;
  • 性价比高;
  • 低电压;
  • 能扩展了多种串行口。

2.1.2 单片机的引脚功能

AT89C52单片机的引脚图如图2-2所示。

图2-2 AT89C52引脚图

  • 电源引脚VCC和VSS
VCC(40引脚):电源端,+5V。
VSS(20引脚):接地端。
  • 外接晶体引脚XTAL 2和XTAL 1
XTAL 2(18引脚):接微调电容和外部晶体的端口。作为振荡电路的输出端。
XTAL 1(19引脚):接微调电容和外部晶体的端口。作为振荡电路的输入端。
  • 控制信号引脚RST、ALE、PSEN、EA
RST(9引脚):复位信号输入端,高电平有效。完成复位操作,输入端必须为两机器周期(即为24个时钟振荡周期)的高电平。
ALE/PROG(30引脚):地址锁存允许信号端。当单片机上电正常工作后,ALE引脚不断向外输出正脉冲信号,此频率为振荡器平率的1/6。输出信号作为锁存低8位地址的控制信号。如果想确认单片机芯片的好坏,可用示波器查看ALE端是否有脉冲信号输出。若有脉冲信号输出,则单片机基本上是好的。
PSEN(29引脚):程序存储允许输出信号端。
EA(31引脚):外部程序存储器地址允许输入端/固化编程电压输入端。
  • 输入/输出端口P0、P1、P2和P3
P0端口(P0.0~P0.7,39~32引脚)
P1端口(P1.0~P1.7)
P2端口(P2.0~P2.7)
P3端口(P3.0~P3.7)
P3端口还用于一些复用功能,如表2-1所示。

表2-1 P3各口线与第2功能表

口线

替代的第2功能

P3.0

RXD(串行口输入)

P3.1

TXD(串行口输出)

P3.2

INT0(外部中断0输入)

P3.3

INT1(外部中断1输入)

P3.4

T0(定时器0的外部输入)

P3.5

T1(定时器1的外部输入)

P3.6

WR(片外数据存储器“写选通控制”输出)

P3.7

RD(片外数据存储器“读选通控制”输出)



2.1.3 单片机控制模块的电路设计

单片机的最小系统如图2-3所示,由单片机芯片、电源、时钟振荡电路与复位电路组成。
时钟振荡电路的设计:
单片机XIAL1和XIAL2分别接30pF的电容,中间再并个12MHz的晶振,形成单片机的晶振电路。电容器C1和C2可稳定频率并对振荡频率有微调作用。
复位电路的设计:
复位操作有按键手动复位和上电自动复位两种。本设计采用的是上电自动复位:RST引脚是复位信号的输入端。复位信号是高电平有效,其有效时间应持续24个振荡周期(即二个机器周期)以上。电容端瞬间通电,电容C通过电阻R充电,RST端为正脉冲,用以复位。只要电源VCC的上升时间不超过1ms,就可以实现自动上电复位,即接通电源就完成了系统的复位初始化。关于参数的选定,在振荡稳定后应保证复位高电平持续时间(即正脉冲宽度)大于2个机器周期。当采用的晶体频率为6MHz时,可取C=22μF,R=1kΩ;当采用的晶体频率为12MHz时,可取C=10μF,R=8.2kΩ。

图2-3 单片机的最小系统图

2.1.4 电源设计

220V交流电转5V直流电的电源设计如图2-4所示是由3个部分组成:变压器、桥式整流电路和三端稳压器。

图2-4 5V直流电电源设计图

  • 变压器:将220V交流电变成9V左右,由此可知变压器变比为220/9=25/1;
  • 桥式整流电路:经过滤波整流后,电压有效值增大为10V。如图2-5所示为桥式整流电路电压波形图;
  • 三端稳压器:一般用于直流电路的保护电路,起到降压、稳压的作用。

图2-5 桥式整流电路电压波形图

2.2温度采集模块的设计

方案一:
传统的测温元件有热电偶和热电阻。一般来说热电偶和热电阻测出的电压,再转换成相应的温度,要比较多外部硬件的支持,其缺点有:硬件电路较复杂;软件调试较复杂;制作成本较高。
方案二:
结合单片机电路的设计,决定使用温度传感器DS18B20,它是最新推出的一种智能型温度传感器,它的优点是可以直接读出被测的温度。主要是对温度信号进行采集和转换工作,电路由DS18B20温度传感器和单片机部分组成。温度传感器DS18B20把收集到的温度送到单片机的P2.6口,单片机接受温度,然后存储下来。因为电路部分只用到了温度传感器和单片机,所以硬件方面比较简单。
方案评价:
方案一这种设计需要用到A/D转换电路,感温电路比较麻烦。但方案二电路比较简单,软件设计容易实现,故实际设计中拟采用方案二。

2.2.1 DS18B20芯片的简介

DS18B20是美国著名半导体公司推出的一种可以直接读出被测温度值的温度传感器,而且采用寄生供电方式与单片机相连,具有成本低和易使用的特点。输出信号为数字信号,方便单片机控制和处理,很多外围电路因此可以减掉。且该芯片的线形较好,物理、化学性也相对稳定,在工业生产中可以用来做测量温度的元件。由于AT89C52能够带多个DSB1820,因此容易实现多点测量的目的。轻松的构建传感器网络,并且单片机可以同时进行数码显示与键盘控制,也可以通过RS232串口与上位机进行数据通讯,达到全方位立体监控的效果。
采用温度芯片DS18B20测量温度,可以更方便的实现多点测温,也体现了数据数字化的好处,便于测温数据集成显示,也方便了后期对数据的处理及其记录。

2.2.2 DS18B20的内部结构

DS18B20芯片的内部结构如图2-6所示。
DS18B20主要包括上下限触发器、储存器与控制逻辑、CRC发生器电源、温度传感器、64位ROM单线借口暂存器。

图2-6 DS18B20芯片的内部结构图

DS18B20温度数字对应关系表如表2-2所示。

表2-2 DS18B20温度数字对应关系表

温度/℃
二进制表示
十六进制表示
+125
0000 0111 1101 0000
07D0H
+85
0000 0101 0101 0000
0550H
+25.0625
0000 0001 1001 0000
0191H
+10.125
0000 0000 1010 0001
00A2H
+0.5
0000 0000 0000 0010
0008H
0
0000 0000 0000 1000
0000H
-0.5
1111 1111 1111 0000
FFF8H


 

DS18B20温度值格式表如表2-3所示。

表2-3 DS18B20温度值格式表

高字节

15

14

13

12

11

10

9

8

S

S

S

S

S

2 6

2 5

2 4

1/0

1/0

1/0

1/0

1/0

64

32

16

低字节

7

6

5

4

3

2

1

0

2 3

2 2

2 1

2 0

2_1

2_2

2_3

2_4

8

4

2

1

0.5

0.25

0.125

0.0625


 

DS18B20的工作过程:
  • 发复位DS18B20的负脉冲;
  • 收DS18B20的回应脉冲;
  • 发ROM命令(33H);
  • 发储存和控制命令。
DS18B20储存控制命令共有6种,如表2-4所示。

表2-4 DS18B20 存储器控制指令

指令

约定代码

复制

48H

读数据

BEH

读电源供电方式

B4H

温度转换

44H

读EERAM

B8H

写数据

4EH

主机操作ROM的命令有5种,如表2-5所示。

表2-5 DS18B20的ROM指令

指令

约定代码

读ROM

33H

匹配ROM

55H

跳过ROM

CCH

搜索ROM

0F0H

报警搜索

ECH

DS18B20的执行序列:
  • 初始化;
  • 执行ROM命令,用于定位;
  • 执行DS18B20的储存控制命令,用于转换和读数据;
  • DS18B20的I/O信号有回应脉冲、复位脉冲、写0,读0,写1,读1等几种。

2.2.3 DS18B20的供电方式

在硬件上,DS18B20与单片机的连接有两种方法,一种是用寄生电源供电,此时,VCC、GND接地,I/O接单片机I/O;另外一种是VCC接外部电源,GND接地,I/O与单片机的I/O线相连。无论是内部寄生电源还是外部供电,I/O口线要接5kΩ左右的上拉电阻。如图2-7所示,本设计采用的是外部电源供电的方式,且选用的上拉电阻为4.7kΩ。

图2-7 DS18B20外部电源供电方式图

2.2.4 DS18B20的引脚功能

引脚功能说明:
  • GND为地;
  • I/O是数据输入/输出脚(单线接口,可作寄生供电);
  • UDD为外接供电电源输入端(在寄生电源接线方式时接地)。
DS28B20的引脚如图2-8所示。

图2-8 DS18B20引脚图

DS18B20的特点说明:
  • 采用单总线技术,与单片机通信只需要一根I/O线,在一根线上可以挂接多个DS18B20。
  • 每只DS18B20具有一个独有的,不可修改的64位序列号,根据序列号访问相应的器件。
  • 低压供电,电源范围从3.0~5.5V,可以本地供电,也可以直接从数据线窃取电源(寄生电源方式)。
  • 测温范围为-55℃~+125℃,在-10℃~+85℃范围内误差为±0.5℃。
  • 可编辑数据为9~12位,转换12位温度时间为750ms(最大)。
  • 用户可自设定报警上下限温度。
  • 报警搜索命令可识别和寻址超过程序限定温度(温度报警条件)的器件。
  • DS18B20的分辨率由用户通过EEPROM设置为9~12位。
  • DS18B20可将检测到温度值直接转化为数字量,并通过串行通信的方式与主控制器进行数据通信。
  • 负电压特性,电源极性接反时,温度计不会因为发热而烧毁,只是不能正常工作。

2.3温度控制模块的设计

方案一:
继电器由于是机械动作,响应速度慢,不能满足本设计的需要。而用可控硅可以在电路中能够实现以小电流控制大电流、交流电的无触点控制的目的,而且它的寿命长、可靠性高、动作快。
方案二:
利用单片机控制双向可控硅的导通角。在不同时刻利用单片机给双向可控硅的控制端发出触发信号,使其导通或关断,实现负载电压有效值的不同,以达到调压控制的目的。具体如下:
(1)由硬件完成过零触发环节,即在工频电压下,每10ms进行一次过零触发信号,由此信号来达到与单片机的同步。
(2)过零检测信号接至单片机输入口,由单片机对此口进行循环检测,然后进行延时触发。
通过单片机控制双向可控硅的导通,从而可以控制加热丝的加热功率。双向可控硅接通,则加热丝加热;双向可控硅断开,则加热丝停止加热。
方案评价:
综合考虑,选择方案二。
由于是弱电控制强电,因而弱电很容易被强电干扰,影响系统的实时性和效率。因此必须需要有抗干扰的措施,将强电与弱电隔离。光耦合器切断了各部件之间的联系,对强电和弱电实施隔离,有效地抑制了干扰信号对电路的干扰。光耦合器很容易得到触发脉冲,且有可靠、体积小的特点。所以可以用带过零检测的光电隔离器MOC3061来驱动双向可控硅并隔离控制回路和主回路。
MOC3061参数:
输出端的额定电压是400V。
最大重复浪涌电流为1.2A。
最大电压上升率dv/dt为1000v/us。
输入输出隔离电压为7500V。
输入控制电流为15mA。
MOC3061引脚排列及内部电路图如图2-9所示。

图2-9 MOC3061引脚排列及内部电路图
当单片机的输出口发出高电平,经过三极管放大后驱动光耦合器的放光二极管,MOC3061的输入端导通,输入电流约为15mA。当MOC306的输出端6脚和4脚尖电压稍稍过零时,光耦内部双向可控硅即可导通,它可以给外部晶闸管一个触发信号,并使其导通;当单片机输出口发出低电平,MOC3061截止,双向可控硅处于截止状态。
MOC3061的优点:
(1)控制简单。
(2)MOC3061由于采用了过零触发电路大大简化了双向可控硅的触发电路。
(3)MOC3061与双向可控硅实际组成了一个固态继电器,实现了无触电控制。
(4)输出通道实现了光电隔离,防止了射电干扰。
(5)单片机输出口直接控制双向可控硅,省去了的D/A转换电路,简化了接口电路。
双向可控硅介绍:
双向可控硅具有双向导通功能,在交流电的正负半周都可以导通。
双向可控硅的通断情况由栅极决定,当栅极无信号时MT1和MT2成高阻态,管截止;当在MT1与MT2之间加一个阈值电压时,就可以利用控制极栅极电压来使可控硅导通。但需要注意的是,当双向可控硅接感性负载时,电流和电压之间有一定的相位差。在电流为零时,反向电压可能不为零,且超过转换电压,使管子反向导通,故要管子能承受这种反向电压,并在回路中加入RC网络加以吸收。
双向可控硅的触发方式:
控制双向可控硅从高阻态转换到导通区可以用不同的方式实现,相应的分为四种方式。
MT1相对于MT2为正,控制脉冲电压Ug相对于MT1为正。
MT1相对于MT2为负,控制脉冲电压Ug相对于MT1为负。
MT1相对于MT2为正,控制脉冲电压Ug相对于MT1为负。
MT1相对于MT2为负,控制脉冲电压Ug相对于MT1为正。
双向可控硅的控制极在触发后便失去了作用。双向可控硅长期维持低阻态,直到低于维持电流I H,然后在转换到高阻态。在控制交流电压时,每次电源电压过零双向可控硅都会自动截止,所以双向可控硅每半个周期都需要重新触发。
如图2-10所示为温度控制模块原理图。

图2-10 温度控制模块原理图

2.4按键及显示模块的设计

方案一:
八段数码管显示,数码管是由八个发光管组成一个八字形,这些段分别由a,b,c,d,e,f,g,dp来表示。
方案二:
LCD1602液晶显示器显示。
方案评价:
本设计采用LCD1602液晶显示器显示,因为它有功耗较低、显示质量较高、重量轻、体积小的特点。
LCD1602的电路图如图2-11所示。

图2-11 LCD1602电路图

2.4.1 LCD1602的参数和引脚功能

LCD1602的参数:
字符尺寸:2.95×4.35(W×H)mm。
显示总容量:16×2个字符。
最佳工作电压:5.0V。
芯片工作电压区间:4.5V—5.5V。
工作电流:2.0mA(5.0V)。
LCD1602的引脚功能如表2-6所示。

表2-6 LCD1602引脚功能表

编号

符号

引脚说明

编号

符号

引脚说明

1

VSS

电源地

9

D2

数据

2

VDD

电源正极

10

D3

数据

3

VL

显示偏压

11

D4

数据

4

RS

数据/命令选择

12

D5

数据

5

R/W

读/写选择

13

D6

数据

6

E

使能信号

14

D7

数据

7

D0

数据

15

BLA

正极背光源

8

D1

数据

16

BLK

负极背光源


2.4.2 LCD1602的特点

在单片机系统中应用晶液显示器作为输出器件有以下几个特点。
(1)功耗较低
LCD1602的功耗主要在驱动IC和内部的电极上,因此功耗较低。
(2)显示质量较高
LCD1602显示器在收到信号后,不需要不断刷新新的亮点,它的显示器上的每一个点可以一直保持同样的亮度和色彩,发光持续稳定。因此,显示器不会闪烁,且质量较高。
(3)重量轻、体积小
因为控制原理不同,LCD1602显示器通过电极来控制液晶分子状态来达到控制的目的,相较于其他的显示器来说,同等面积的显示器,LCD1602要轻许多。
(4)数字式接口
液晶显示器都是数字式的,和单片机系统的接口更加简单可靠,操作更加方便。

2.4.3 按键电路的设计

方案一:
独立连接式。独立式按键是指各按键相互独立地接通一条输入数据线。
方案二:
行列式(矩阵式)为了减少键盘与单片机借口时所占用I/O线的数目,在键数较多时,通常都将键盘排列成行列矩阵形式。判断键盘中哪一个键被按下是通过将行线逐行置低电平后,检查列输入状态实现的。
方案评价:
对比两种方案可知,方案一虽然也能很好的实现电路的要求,但考虑到电路设计的成本和电路整体的性能,我们采用方案一。
如图2-12所示为独立式按键电路图。

图2-12 独立式按键电路图

独立式按键是指各按键相互独立地接通一条输入数据线。
本设计采用2个独立式按键分别连接单片机I/O来实现按键的功能。从而解决了单片机I/O口被占用的问题和减少了硬件的复杂程度,通过软件来配合2个按键实现功能。系统程序中通过扫描P1.2、P1.3这2个端口是否为低电平0来判断按键是否被按下。

2.5报警模块的设计

方案一:
使用7406作驱动的单音频报警电路。
方案二:
使用三极管作驱动的单音频报警电路。
方案评价:
使用方案二。
蜂鸣器电路图如图2-13所示。

图2-13 蜂鸣器电路图

蜂鸣器以直流电压作为电源,被广泛地应用于电话机、电子玩具、报警器、定时器等电子产品中,被用来当作电子发声器。蜂鸣器主要有压电式和电磁式两种。本设计的报警模块主要采用蜂鸣器及发光二级管的蜂鸣和发光来实现超出温度上限时的报警。
压电式蜂鸣器约需10mA的驱动电流。单片机的P2.5接晶体管基极输入端。当P2.5输出高电平1时,三极管导通,压电蜂鸣器两端获得约+5V电压而鸣叫;当P2.5口输出低电平0时,三极管截止,蜂鸣器停止发声。
要使三极管有放大作用,必须保证发射结正偏、集电极反偏。
电流放大系数:β=IC/IB。
9013三极管介绍:
9013 结构:NPN。
集电极-发射极电压:25V。
集电极-基电压:45V。
射极-基极电压:5V。
集电极电流:0.5A。
耗散功率:0.625W。
结温:150℃。
特征频率最小:150MHz。
放大倍数:91。


3软件设计

按照系统设计功能的要求,来确定本系统程序包括DS18B20读温度程序、LCD1602的显示程序、键盘扫描程序、报警处理程序以及继电器加热程序。

3.1主程序的设计

如图3-1所示为主程序流程图。

图3-1 主程序流程图

3.2DS18B20读温度程序的设计

(1)DS18B20读时序:
  • 读时序包括读0和读1的时序。
  • 读时序是在拉低单总线之后,在15us之内释放单总线,让DS18B20把数据传送到单总线上。读时序的过程至少需要60us。
(2)DS18B20写时序:
  • 写时序包括写0和写1的时序。
  • 写0和写1时序略有不同。当写0时序时,单总线至少要被拉低60us。保证DS18B20能够采到数据线上的“0”电平,在15us到45us之间;当写1时序时,拉低单总线,并在15us之内释放单总线。
如图3-2所示为DS18B20读温度程序流程图。

图3-2 DS18B20读温度程序流程图

3.3键盘扫描程序的设计

该电路为查询方式电路,当任何一个键按下时,与之相连的输入数据线即被清0,而平时该线为1。因此可以通过检测各数据线的状态(0或1)来判断按键是否闭合,以及哪个按键已闭合。
如图3-3所示为键盘扫描程序流程图。

图3-3 键盘扫描程序流程图

3.4报警处理程序的设计

设定目标温度上限,当实际温度大于目标温度上限的时候,执行声光报警程序。
如图3-4所示为声光报警程序流程图。

图3-4 声光报警程序流程图

3.5PID控制算法

    本设计采用了PID控制技术。在工程实际运用中,PID控制器以其稳定性好、工作可靠、调整方便、结构简单而成为主要的工业控制技术之一。当被控对象的参数和结构不能被很好的掌握,或得不到精确的数学模型时,控制理论的技术很难被采用,所以当系统控制器的结构和参数必须依靠经验来确定时,PID控制技术最为实用和方便。

PID调节器是一种线性调节器,它将给定值r(t)与实际输出值c(t)的偏差的比例(P)、积分(I)、微分(D)的组合组成控制量,从而达到对控制对象的控制目的。控制偏差

              

                   (3-1)
(1)连续控制系统PID调节器的微分方程为:
              

                (3-2)
式中
Kp——比例常数;
Ti——积分时间常数;
Td——微分时间常数;
e(t)——系统偏差信号;
u(t)——控制器的输出信号。
(2)PID调节器的函数形式方程为:
              

                      (3-3)
(3)数字PID控制器
如表3-1所示为模拟PID控制规律的离散化表。

表3-1 模拟PID控制规律的离散化

模拟形式

离散化形式

数字PID控制器的差分方程:

              

              (3-4)

为积分系数。

为微分系数。

式中  

              称为比例项。

      

         称为积分项。

      

  称为微分项。

常用的控制方式:

   1、P控制          

2、PI控制         

3、PD控制         

4、PID控制        

模拟PID控制系统原理如图3-5所示。

图3-5 模拟PID控制系统原理框图

(4)PID调节器比例、积分、微分的环节
  • 比例环节:把调节器的输入偏差乘以一个系数,作为调节器的输出,比例环节的作用是放大误差的幅值。当仅有比例控制环节时系统输出存在稳态误差。
  • 积分环节:调节器加入积分环节后达到消除稳态误差的目的。积分项随着时间的增加而增大,积分项对稳态误差的消除取决于时间的积分。PI调节器可以使系统在进入稳态后无稳态误差。
  • 微分环节:调节器的输入、输出误差信号的微分成正比关系。微分环节能反应偏差信号的变化趋势,从而可以实现超前调节。 控制器中仅有比例环节是不行的,还需要增加微分项,因为它能预测误差变化的趋势。
  • PID控制算法的两种类型
  • 位置型控制
              

              (3-5)
  • 增量型控制
              

              (3-6)
PID参数整定方法:
  • 理论计算法――依赖被控对象准确的数学模型。
  • 工程整定法――不依赖被控对象准确的数学模型,直接在控制系统中进行现场整定。
    下面对PID运算加以说明:
    所有的数都变成定点纯小数进行处理。
    算式中的各项有正有负,以最高位作为符号位,最高位为0表示为正数,为1表示负数。正负数都是补码表示,最后的计算以原码输出。
节16位进行计算,最后将运算结果取成高8位有效值输出。输出控制量u(n)的限幅处理。为了便于实现对晶闸管的通断处理,PID的输出在0~250之间。大于250或小于0的控制量u(n)都是没有意义的,因在算法上对u(n)进行限幅,即:

                       

=

         (3-7)

增量式PID控制算法如图3-6所示。

图3-6 增量式PID控制算法程序框图


4系统仿真

单片机程序编写可以有多种:汇编语言、C语言等。本设计采用C语言来编写。
  • 汇编语言
用汇编语言助记符来表示的程序就是汇编语言。这种语言比机器语言更容易,使用方便,容易记忆。但是由于不同的机器对应着不同的汇编语言,这种语言具有一定限制。
  • C语言
  • 对微控制器的指令系统不需要了解,只是有一个初步的了解单片机的存储结构。
  • 具有规范的程序,通过不同的函数,是程序变得结构化。
  • 寄存器分配,不同的内存地址和数据类型和其他细节可以由编译器管理。
  • 大大缩短了编程和调试的时间,提高了编程的效率。
对于AT89C52的控制设计,编程用Keil软件,仿真用proteus软件。Keil支持C语言、汇编及二者的混合编程。
编程软件Keil介绍:
KeiluVision2是美国软件公司的C语言软件开发系统,它兼容单片机系统。与汇编相比,C语言有易学易用的特点。不仅提高了工作效率,而且在关键的位置嵌入汇编,可以使程序的工作效率接近汇编。标准C编译器在保留汇编代码搞笑、快速特点的同时,还未控制器的软件开发提供了C环境。uVision2的集成开发环境已经完全包括了C52。它包括:项目管理器、编译器,汇编器,实时操作系统和调试器。Keil软件界面如图4-1所示。
仿真软件Protues介绍:
Protues软件是英国公司出版的工具软件。它不仅具有仿真功能,还能仿真单片机及外围器件。它是目前最好的仿真单片机及外围器件的工具。在国内它已受到学单片机的爱好者和参加单片机开发应用工作者的好感。Proteus是世界上最著名的仿真软件之一,从代码调试到原理图布图等仿真,从概念到产品的整个流程都是它的功劳。目前它是世界上唯一可以将PCB设计软件、电路仿真软件和虚拟模型仿真软件合为一的软件之一,它的处理器模型支持MSP430、AVR、8051、HC11、ARM和8086PIC10/12/16/18/24/30/DsPIC33等,在编译方面,它也支持Keil、IAR和MPLAB等多种编译器。
Proteus ISIS的运行界面是标准的Windows界面,如图4-3所示,Proteus ISIS软件有:标题栏、主菜单、状态栏、标准工具栏、绘图工具栏、对象选择按钮、仿真进程控制按钮、预览窗口、图形编辑窗口、对象选择器等窗口。

图4-1 Keil软件界面

生成Hex文件,如图4-2所示。

图4-2 生成Hex文件图

图4-3 Proteus软件界面

当温度还未达到设置温度上限默认的50℃时,如图4-4所示单片机P2.5口输出低电平,蜂鸣器不响。单片机P2.7口也输出低电平,二极管不亮,继电器继续加热。

图4-4 温度低于上限时仿真图

  当温度达到设置温度上限默认的50℃时,如图4-5所示单片机P2.5口输出高电平,蜂鸣器响。单片机P2.7口也输出高电平,二极管亮,继电器停止加热。

图4-5 温度低于上限时仿真图
结论

通过本次设计,加深了我对单片机的认识,对温度传感器DS18B20也有了更深刻的了解。虽然DS18B20在测量温度时,出现了灵敏度不高,无法跟随温度变化快速显示温度等问题,但是易于制作、价格低廉、硬件结构简单、测量值精确和易于操作等许多优点让DS18B20在测温方面有独特的优势。


参考文献

[1]陈焕生.温度测试技术及仪表[M].北京:水利电力出版社,1987.9.
[2]秦沿海.数字PID控制原理及其应用[J].西南民族学院学报,1997:49-54.
[3]徐科军.传感器与检测技术[M].北京:电子工业出版社,2004.9.
[4]张宝芬.自动检测技术及仪表控制系统[M].北京:化学工业出版社,2000.
[5]先锋工作室.单片机程序设计实例[M].北京:清华大学出版社,2003.
[6]王孝武.现代控制理论基础[M].北京:机械工业出版社,1998.
[7]袁希光.传感器技术手册[M].北京:国防工业出版社,1986.
[8]刘剑.一种数字PID控制算法分析[J].承德石油高等专科学校学报,2007:11-22.
[9]历风满.数字PID控制算法的研究[J].辽宁大学学报,2005:367-370.
[10]丁元杰.单片微机原理及应用[M].北京:机械工业出版社,1996:256-276.
[11]赵鸿图.基于单片机的温度控制系统的设计与实现Ⅱ[J].微计算机信息,2008(26).
[12]杨万超.S1单片机温度控制系统设计Ⅱ[J].黑龙江科技信息,2009(29).
[13]赖寿宏.微型计算机控制技术[M].北京:机械工业出版社,2003:130-145.
[14]马淑兰.单片机技术及应用实例分析[M].西安:西安电子科技大学出版社,2009:20-40.
[15]Zhang et al.Digital PID controller design for multivariable analogue systems with computational[J].IMA J Math Control Info,2004:21-433.
[16]L Dubois.Temperature control by microwave radiometry with narrow band width [J].EurPhysJ.App.lPhys,2000:63-68.
[17]Shiqian wu,Meng Joo Er and Yang Gao,A Fast Appoach for Automatic Generation of Fuzzy Rules by Generalized DynamicFuzzy Neural Networks[J]. IEEE Transaction on Fuzzy Systems,2001(4):578-593.



致谢

本设计在***老师的严格要求和悉心指导下才完成,从课题选择、总体方案设计、硬件软件设计到系统仿真,无不凝聚着程老师的汗水和心血,导师无私的关怀和悉心的指导,令我受益匪浅。在此特向程老师表示深深的感谢和崇高的敬意。


附录

附录1

附录2
程序代码:
  1. #include <at89x51.h>
  2. #include <absacc.h>
  3. #include <ctype.h>
  4. #include <math.h>
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <DS18B20.h>
  8. #include "LCD1602.h"                                          液晶显示头文件
  9. #define uchar unsigned char
  10. #define uint unsigned int
  11. sbit Key1=P1^0;
  12. sbit Key2=P1^1;
  13. sbit Up  =P1^2;
  14. sbit Down=P1^3;
  15. uchar t[2],*pt;                                                        //这是用来存放温度值的,测温程序通过这个数组与主函数通信
  16. uchar  TempBuffer1[9]={0x2b,0x31,0x32,0x32,0x2e,0x30,0x30,0x43,'\0'};
  17.                                                                                                                 //显示实时的温度,上电时显示+125.00C
  18. uchar  TempBuffer0[17]={0x54,0x48,0x3a,0x2b,0x31,0x32,0x35,0x20,
  19.                                                                                                                 0x54,0x4c,0x3a,0x2b,0x31,0x32,0x34,0x43,'\0'};
  20.                                                                                                                 //显示温度上下限,上电时显示TH:+125 TL:+124C                                                                                                
  21. uchar code dotcode[4]={0,25,50,75};
  22. uchar set;//温度初始值
  23. uchar count,high_time=0; //调节占空比的参数
  24. uint rout;// PID输出
  25. /查表法*******
  26. 将表值分离出的十位和个位送到十分位和百分位********************/
  27. struct PID
  28. {
  29.               uint SetPoint;      // 设定目标 Desired Value
  30.               uint Proportion;    // 比例常数 Proportional Const
  31.               uint Integral;      // 积分常数 Integral Const
  32.               uint Derivative;    // 微分常数 Derivative Const
  33.               signed int LastError;     // 错误Error[-1]
  34.               signed int PrevError;     // 错误Error[-2]
  35.               signed int SumError;      // Sums of Errors
  36. };
  37. struct PID spid;                // PID控制结构体
  38. void init_pid()
  39. //PID初始化
  40. {
  41.               high_time=50;
  42.               spid.Proportion = 23;       // Set PID Coefficients
  43.               spid.Integral = 2;
  44.               spid.Derivative =6;
  45.               spid.SetPoint = set;      // Set PID Setpoint
  46. }
  47. unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint )
  48. //PID算法
  49. {
  50.               signed int dError,Error;
  51.               Error = pp->SetPoint - NextPoint;           // 偏差
  52.               pp->SumError += Error;                      // 积分
  53.               dError = pp->LastError - pp->PrevError;     // 当前微分
  54.               pp->PrevError = pp->LastError;            
  55.               pp->LastError = Error;
  56.               return (pp->Proportion * Error+ pp->Integral * pp->SumError              + pp->Derivative * dError);
  57. }
  58. void duty_cycle(uint t)                              
  59. // 占空比
  60. {
  61.               uchar s;
  62.               t=t/10;
  63.               s=set;
  64.               if(s>t)
  65.               {
  66.                             if(s-t>2)
  67.                                           high_time=100;
  68.                             else
  69.                             {
  70.                                           rout = PIDCalc ( &spid,t );   // Perform PID Interation
  71.                                           if(high_time<=100)
  72.                                                         high_time=(uchar)(rout/600);
  73.                                           else
  74.                                                         high_time=100;            
  75.                             }
  76.               }
  77.               else
  78.                             high_time=0;
  79. }
  80. void covert0( unsigned char TH, unsigned char TL)              //将温度上下限转换为LCD显示的数据
  81. {
  82.               if(TH>0x7F)                    //判断正负,如果为负温,将其转化为其绝对值
  83.               {
  84.                             TempBuffer0[3]=0x2d;                   //0x2d为"-"的ASCII码
  85.                             TH=~TH;
  86.                             TH++;
  87.               }
  88.               else TempBuffer0[3]=0x2b;              //0x2B为"+"的ASCII码
  89.             
  90.               if(TL>0x7f)
  91.               {
  92.                             TempBuffer0[11]=0x2d;                   //0x2d为"-"的ASCII码
  93.                             TL=~TL+1;
  94.               }
  95.               else
  96.                             TempBuffer0[11]=0x2b;              //0x2B为"+"的ASCII码
  97.             
  98.               TempBuffer0[4]=TH/100+0x30;                                         //分离出TH的百十个位
  99.               if( TempBuffer0[4]==0x30)
  100.                             TempBuffer0[4]=0xfe; //百位数消隐
  101.               TempBuffer0[5]=(TH%100)/10+0x30;                                                        //分离出十位
  102.               TempBuffer0[6]=(TH%100)%10+0x30;                                                        //分离出个位
  103.               TempBuffer0[12]=TL/100+0x30;                                         //分离出TL的百十个位
  104.               if( TempBuffer0[12]==0x30)
  105.                             TempBuffer0[12]=0xfe; //百位数消隐
  106.               TempBuffer0[13]=(TL%100)/10+0x30;                                                        //分离出十位
  107.               TempBuffer0[14]=(TL%100)%10+0x30;                                                        //分离出个位
  108. }
  109. void covert1(void)              //将温度转换为LCD显示的数据
  110. {
  111.               unsigned char x=0x00,y=0x00;
  112.                  t[0]=*pt;
  113.                  pt++;
  114.                  t[1]=*pt;
  115.                  if(t[1]>0x07)                    //判断正负温度
  116.                  {
  117.                   TempBuffer1[0]=0x2d;                   //0x2d为"-"的ASCII码
  118.                             t[1]=~t[1];                                          /*下面几句把负数的补码*/
  119.                             t[0]=~t[0];                             /* 换算成绝对值*********/
  120.                             x=t[0]+1;                                                        /***********************/
  121.                             t[0]=x;                                                                      /***********************/
  122.                             if(x>255)                /**********************/
  123.                                           t[1]++;                                                        /*********************/
  124.                  }
  125.                  else
  126.                             TempBuffer1[0]=0x2b;              //0xfe为变"+"的ASCII码
  127.                 t[1]<<=4;                            //将高字节左移4位
  128.                 t[1]=t[1]&0x70;                            //取出高字节的3个有效数字位
  129.                 x=t[0];                                                                      //将t[0]暂存到X,因为取小数部分还要用到它
  130.                 x>>=4;                                                                      //右移4位
  131.                 x=x&0x0f;                                                                      //和前面两句就是取出t[0]的高四位            
  132.                 t[1]=t[1]|x;                                          //将高低字节的有效值的整数部分拼成一个字节
  133.                 TempBuffer1[1]=t[1]/100+0x30;                                         //+0x30 为变 0~9 ASCII码
  134.                  if( TempBuffer1[1]==0x30)
  135.                             TempBuffer1[1]=0xfe; //百位数消隐
  136.                 TempBuffer1[2]=(t[1]%100)/10+0x30;                                                        //分离出十位
  137.                 TempBuffer1[3]=(t[1]%100)%10+0x30;                                                        //分离出个位
  138.                 t[0]=t[0]&0x0c;                                                                                                  //取有效的两位小数
  139.                 t[0]>>=2;                                                                                                                              //左移两位,以便查表
  140.                 x=t[0];                                                                                                                                          
  141.                 y=dotcode[x];                                                                                                                              //查表换算成实际的小数
  142.                 TempBuffer1[5]=y/10+0x30;                                                                                                  //分离出十分位
  143.                 TempBuffer1[6]=y%10+0x30;                                                                                                  //分离出百分位
  144. }                                         
  145. void delay(unsigned int i)
  146. {
  147.               while(i--);
  148. }
  149. void t0_int(void) interrupt 1                            //PWM波输出
  150. {
  151.               if(++count<=(high_time))
  152.               Relay=0;
  153.               else if(count<=100)
  154.               Relay=1;
  155.               else
  156.               count=0;
  157.               TH0=0X20;
  158.               TL0=0X00;
  159. }
  160. main()
  161. {
  162.               unsigned char TH=50,TL=10,temp=0;                                                                          //下一步扩展时可能通过这两个变量,调节上下限
  163.                                                                                                                        //测温函数返回这个数组的头地址
  164.               TMOD=0X01;
  165.               TH0=0X20;
  166.               TL0=0X00;
  167.               EA=1;
  168.               ET0=1;
  169.               TR0=1;
  170.               set=60;//目标温度
  171.               Beep=0;Relay=0;
  172.               init_pid();
  173.               while(1)
  174.               {            
  175.                   if(Up==0)
  176.                             {
  177.                                while(!Up);
  178.                                TH++;
  179.                             }
  180.                             if(Down==0)
  181.                             {
  182.                                           while(!Down);
  183.                                           TL--;
  184.                             }
  185.                             pt=ReadTemperature(TH,TL,0x3f);                            //上限温度-22,下限-24,分辨率10位,也就是0.25C
  186.                                                                                                                                                           //读取温度,温度值存放在一个两个字节的数组
  187.                
  188.                   if((t[1]>TH)|(t[1]<TL))
  189.                             {
  190.                                 Beep=1;
  191.               //                            Relay=1;
  192.                            
  193.                             }
  194.                             else
  195.                             {
  196.                                 Beep=0;
  197.               //                            Relay=0;
  198.                             }
  199.                             delay(10000);
  200.                             covert1();
  201.                             covert0(TH,TL);
  202.                             LCD_Initial();                                                                                                  //第一个参数列号,第二个为行号,为0表示第一行
  203.                                                                                                                                                                         //为1表示第二行,第三个参数为显示数据的首地址
  204.                             LCD_Print(0,0,TempBuffer0);            
  205.                             LCD_Print(0,1,TempBuffer1);                                                        
  206.               }
  207. }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Go GORM介绍

GORM 是一个功能强大的 Go 语言 ORM&#xff08;对象关系映射&#xff09;库&#xff0c;它提供了一种方便的方式来与 SQL 数据库进行交互&#xff0c;而不需要编写大量的 SQL 代码。 GORM的关键特性 全功能的ORM&#xff1a;支持几乎所有的ORM功能&#xff0c;包括模型定义、基…

揭秘C++ String容器:字符串操作的艺术

目录 ​编辑 引言 一、初识std::string&#xff1a;构造与初始化 二、字符串的操纵艺术&#xff1a;拼接、查找与替换 三、访问与遍历&#xff1a;字符的细腻触感 四、大小与容量&#xff1a;动态调整的智慧 五、进阶功能&#xff1a;探索更多可能 结语 引言 在C标准库…

vue3+electron+typescript 项目安装、打包、多平台踩坑记录

环境说明 这里的测试如果没有其他特别说明的&#xff0c;就是在win10/i7环境&#xff0c;64位 创建项目 vite官方是直接支持创建electron项目的&#xff0c;所以&#xff0c;这里就简单很多了。我们已经不需要向开始那样自己去慢慢搭建 yarn create vite这里使用yarn创建&a…

特殊变量笔记3

输入一个错误命令, 在输出$? 特殊变量&#xff1a;$$ 语法 $$含义 用于获取当前Shell环境的进程ID号 演示 查看当前Shell环境进程编号 ps -aux|grep bash输出 $$ 显示当前shell环境进程编号 小结 常用的特殊符号变量如下 特殊变量含义$n获取输入参数的$0, 获取当前She…

将3D检测的box框投影到BEV图片上

前言 点云数据作为一种丰富的三维空间信息表达方式&#xff0c;通常用于自动驾驶、机器人导航和三维建模等领域。然而&#xff0c;点云数据的直观性不如二维图像&#xff0c;这限制了它在一些需要快速视觉反馈的应用场景中的使用。本文将探讨如何将点云数据转换为二维图像&…

Thymeleaf 搭建家居网首页

文章目录 1.引入Thymeleaf sunliving-commodity模块1.在resources目录下引入Thymeleaf 所需资源2.pom.xml引入Thymeleaf依赖3.application.yml 关闭缓存&#xff0c;使页面实时刷新4.在application-prod.yml开启缓存5.编写com/sun/sunliving/commodity/web/IndexController.jav…

OpenUI 可视化 AI:打造令人惊艳的前端设计!

https://openui.fly.dev/ai/new 可视化UI的新时代&#xff1a;通过人工智能生成前端代码 许久未更新, 前端时间在逛github&#xff0c;发现一个挺有的意思项目&#xff0c;通过口语化方式生成前端UI页面&#xff0c;能够直观的看到效果&#xff0c;下面来给大家演示下 在现代…

idea2023的git从dev分支合并到主分支master

1.本地项目切换到主分支master 右键项目-git-Branches 依次点击项目-Remote-Origin-master-CheckOut 现在你的idea中的这个项目就是远程master分支的代码了。 2.合并dev分支到master 右击项目-git-Merge 选择origin-dev 点击Merge按钮&#xff0c;此时只是合并到本地的maste…

Weblogic XML反序列化漏洞 [CVE-2017-10271]

漏洞环境搭建请参考 http://t.csdnimg.cn/i11e2 漏洞原理 Weblogic的wls security组件对外提供webservice服务&#xff0c;wls security组件使用了xmldecoder来解析用户传入的xml数据&#xff0c;如果用户进行xml恶意数据的构造&#xff0c;即可触发反序列化漏洞 漏洞版本 O…

【MySQL】聊聊count的相关操作

在平时的操作中&#xff0c;经常使用count进行操作&#xff0c;计算统计的数据。那么具体的原理是如何的&#xff1f;为什么有时候执行count很慢。 count的实现方式 select count(*) from student;对于MyISAM引擎来说&#xff0c;会把一个表的总行数存储在磁盘上&#xff0c;…

Dbs封装_连接池

1.Dbs封装 每一个数据库都对应着一个dao 每个dao势必存在公共部分 我们需要将公共部分抽取出来 封装成一个工具类 保留个性化代码即可 我们的工具类一般命名为xxxs 比如Strings 就是字符串相关的工具类 而工具类 我们将其放置于util包中我们以是否有<T>区分泛型方法和非泛…

pycharm连接阿里云服务器过程记录

因为不想用自己的电脑安装anaconda环境,所以去查了一下怎么用服务器跑代码,试着用pycharm连接阿里云服务器,参考了很多博客,自己简单配置了一下,记录一下目前完成的流程. 主要是:阿里云服务器的远程登录和安装anaconda,以及怎么用pycharm连接阿里云服务器上的解释器. 小白刚开始…

Java进阶学习笔记27——StringBuilder、StringBuffer

StringBuilder&#xff1a; StringBuilder代表可变字符串对象&#xff0c;相当于一个容器&#xff0c;它里面装的字符串是可以改变的&#xff0c;就是用来操作字符串的。 好处&#xff1a; StringBuilder比String更适合做字符串的修改操作&#xff0c;效率会更高&#xff0c;…

【FPGA】Verilog:奇校验位生成器的实现(Odd Parity bit generator)

解释奇数奇偶校验位生成器和检查器的仿真结果及过程。 真值表和卡洛图: Odd Parity Bit Generator A B C

利用element实现简单右键

利用element-plus中的el-menu实现简单右键 实现如下 <template><main class"mainClass" contextmenu"showMenu($event)"> </main><el-menu:default-active"1"class"el-menu-demo"mode"vertical":col…

GitHub怎么修改个人资料名称name和用户名username

文档 GitHub•GitHub文档•Get started•帐户和个人资料•配置文件•自定义个人资料•个性化设置https://docs.github.com/zh/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/personalizing-your-profile GitHub•GitHub文档•G…

从XPS迁移到IP Integrator

从XPS迁移到IP Integrator 概述 AMD Vivado™设计套件IP集成器可让您将包含AMD的设计缝合在一起 IP或您的自定义IP在相对较短的时间内&#xff0c;在GUI环境中工作。 就像在Xilinx Platform Studio中一样&#xff0c;您可以快速创建嵌入式处理器设计&#xff08;使用&#xff0…

【STM32】新建工程(江科大)

文章目录 STM32的开发方式库函数文件夹一、新建一个基于标准库的工程1.建立一个存放工程的文件夹2.打开Keil5 二、通过配置寄存器来完成点灯1.配置RCC寄存器2.配置PC13口&#xff08;1&#xff09;配置PC13口的模式&#xff08;2&#xff09;给PC13口输出数据 三、为寄存器添加…

5.26牛客循环结构

1002. 难点&#xff1a; 两层循环条件设置 思路 可以设置三个变量 代码 1003 思路&#xff1a; 与星号双塔差不多&#xff0c;在此基础上加大一点难度 每日练题5.23 &#xff08;EOF用法&#xff09;-CSDN博客 代码 1004 代码

微信小程序如何跳转微信公众号

1. 微信小程序如何跳转微信公众号 1.2. 微信公众号配置 登录微信公众号&#xff0c;点击【小程序管理】&#xff1a;   点击【添加】&#xff1a;   点击【关联小程序】&#xff1a;   输入小程序进行关联&#xff1a; 1.2. 微信小程序配置 登录微信小程序&#xf…