失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > AutoLeaders控制组——51单片机学习笔记(定时器 串口通信)

AutoLeaders控制组——51单片机学习笔记(定时器 串口通信)

时间:2020-12-28 14:05:01

相关推荐

AutoLeaders控制组——51单片机学习笔记(定时器 串口通信)

本篇内容是观看B站江科大自化协UP主的教学视频所做的笔记,对其中内容有所引用,并结合自己的单片机板块进行了更改调整。

以下笔记内容以一个视频为一个片段(内容较多,可能不适合速食,望见谅)

一些内容涉及前面的知识点,可能需要提前了解(可以翻看本人之前的文章或者去B站看UP主的视频)

目录

7-1、定时器

定时器介绍

作用:

STC89C52定时器资源

原理:

定时器工作模式:

中断系统

定时器和中断系统

总连接内部结构

定时器相关寄存器

中断寄存器:

7-2、按键控制LED流水灯模式

代码一:

Ⅰ、新建工程与main.c文件

Ⅱ、编写配置寄存器的子函数

Ⅲ、编写中断时调用的函数

Ⅳ、将定时器函数进行模块化

Ⅴ、将需要的之前写过的模块化代码拷贝到工程文件中

Ⅵ、编辑主函数文件

Ⅶ、烧录程序

代码二:

Ⅰ、新建工程与main.c文件

Ⅱ、添加需要的模块化文件到工程目录下

Ⅲ、编译主函数文件

Ps:

8-1、串口通信

串口介绍:

补充小知识:

串口连接

一些基本知识

电平标准

常见通信接口比较

相关术语

51单片机的UART

串口参数及时序图

①波特率:

②检验位

③停止位

串口模式图

串口内部线路

串口相关寄存器

8-2、串口向电脑发送数据&电脑通过串口控制LED

程序一

写入代码

Ⅰ、新建工程及main.c文件

Ⅱ、添加已有的模块化文件进工程目录。

Ⅲ、配置相关的寄存器

Ⅳ、配置主函数内容

模块化对应代码

Ⅰ、新建UART.c文件,将代码移植(剪切)过去。

Ⅱ、新建UART.h文件,将模板及声明编写。

Ⅲ、在程序一中验证效果。

程序二

写入代码

Ⅰ、获取工程文件。

Ⅱ、更改配置寄存器的模块化代码

Ⅲ、编写中断函数

Ⅳ、烧录程序

波特率的计算(以UP主的12MHZ晶振频率为例)

总结:如非必要,可以直接用STC烧录软件进行生成即可。

数据显示模式

7-1、定时器

定时器介绍

51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成。

(区别于之前用I/O口控制的独立按键,数码管等,那些属于外设)

作用:

(1)用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作。

(2)替代长时间的Delay,提高CPU的运行效率和处理速度。(避免单纯Delay导致的CPU占用)

(3)一条线执行多任务时,负责切换某个任务执行。

(…)

STC89C52定时器资源

定时器个数:3个(T0、T1、T2),T0和T1与传统的51单片机兼容,T2是此型号单片机增加的资源。(新版本兼容老版本,因此有T0与T1)

注意:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0和T1的操作方式是所有51单片机所共有的。

因此,需要预先搜索一下对应的单片机手册(购买时附带资料),确定其相关资源。

原理:

其中“一秒”是指一个固定时间段,不是指一秒。

中断系统:相当于消息提醒机制,是51单片机内部资源。

定时器工作模式:

模式1连接方式:

可以将其分为三部分:

计数系统:

TL0:Timer Low 0,存储低字节的数(一个字节存储空间)

TH0:Timer High 0,存储高字节的数(一个字节存储空间)

二者合起来可以存储65535个数(从0到65535,0不储存,作为一种状态)

TF0:Timer Flag 0,标志位置。每当存储数超过65535时,会产生溢出,存储变为0,并置一个标志位,该标志位向中断系统申请中断。

定时器时钟:

①时钟部分:

这里的晶振以自己单片机的为准(本单片机与UP主的单片机晶振不同,为11.0595MHZ)。

内部应该是压电陶瓷,会发出固定频率的振动,根据这种信号产生固定的频率。

其中上面的T0 Pin位于单片机的一个I/O口连接部分

当连接外部时钟后,单片机内部的定时器变为计数器,当外部每次传入一个脉冲时加一,起计数器的功能。

②分屏部分:

当分屏部分与上面的+12相连时,那么就会把12MHZ的信号进行12分屏,于是输出频率变为1MHZ(1MHZ的一个周期为一微秒,在后面的计数系统记一次数)

③选择开关模式部分:

其中C/T(T上带一横杠)为寄存器的一位,当配置为1时,为C(counter,计算器)模式,向下连接;

当配置为0时,为T(Timer,定时器)模式,向上连接。(上面带一横杠,意味着低电平0)

中断系统

中断系统解释:

提取:

中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的;

其中请求CPU中断的为中断源;

根据中断源的轻重缓急划分等级,先处理高等级,再到低等级;

中途出现的高等级中断源请求可以打断低等级的中断源。

中断程序流程图:

相当于同时执行两段程序(实际上是打断去执行其他内容,但是打断时间短,约等于同时执行)。

STC89C52中断资源:

①中断源个数:8个。

下面是来自手册的查询:

②中断源优先级个数:4个。

③中断号:在函数后面加入interrupt 数字;即可成为中断的入口。

定时器和中断系统

总连接内部结构

下面与定时器相连的是传统的51单片机中断系统图,上面是手册中的中断系统图。

如果定时器后面不连接中断系统也可以,但是主程序无法检测到定时器响应,但是仍然可以用查询的方式查询TF0这个标志位进行检测(可能不方便)。

最终连接效果:

定时器相关寄存器

操作模式——单片机通过配置寄存器来控制内部线路的连接,通过内部线路的不同连接方式来实现不同电路,不同电路完成不同功能。

通过配置这些寄存器,实现上面总连接结构图中的电路连接。(在特定的地址写入值进行配置)

定时器的相关寄存器的介绍:

①寄存器TCOM(Timer Control)

TR0:(这里暂时不用管这个计数的GATE控制先,后面有需要可以再了解)

TF0:不需要写,只需要读取该位查询中断。

②寄存器TMOD(Timer Mode)

通过控制GATE对应的TMOD位,可以实现外部时钟与内部时钟一同控制定时器开关(全部给1才接通,有0不接通)

下面画圈部分,利用与或非门,实现上面的控制开关功能。

③其他相关寄存器

中断寄存器:

结合需要的连接电路图,寻找对应的寄存器口进行配置。

①IE部分的寄存器

②IP部分的寄存器

7-2、按键控制LED流水灯模式

代码一:

实现效果:通过独立按键K1,实现按下按键时,转换LED流水灯的方向,同时没有间隔延迟,较为流畅的转换。

Ⅰ、新建工程与main.c文件

Ⅱ、编写配置寄存器的子函数

Ps:在头文件有声明的内容才能用。(这里的REGX52文件已经包含有,所以能使用)

①编写函数模板

②配置TMOD寄存器

对定时器1的内容配置:

利用上节提到的,先不管定时器1,设置为0000(因为这里只使用定时器0);

(这里根据手册来说,后两位应该设置为11,这样才使得定时器1无效)

对定时器0的内容配置:

GATE不使用,配置为0;

C/T(T上有横杠)设置为定时器模式(T模式),设置为低电平0;

M1与M0两位共同决定定时器/计数器的模式,这里设置为16位定时器,因此设置为01。

(下图为解释M1与M0配置对应的模式)

最终在代码写入配置:

补充:

不可位寻址的寄存器只能整体赋值,可位寻址的寄存器可以对其中的每一位单独赋值。

例如:上面的TMOD标有不可位寻址,因此只能整体赋值。

而之前使用的P0~P3寄存器都是可位寻址的,因此我们之前能用P2_1之类进行单独赋值。

③配置TCON寄存器

可见该寄存器是可位寻址的,因此下面我们采用单独赋值方法。

清除中断标志位:

将TF0赋值为0,将标志位清零。

原因:一旦标志位等于1时,就会产生中断。(当然不配置影响也不大,就是有随机性)

TF0位说明:

配置定时器0工作:

将TR0赋值为1,电机开始工作。

TR0位说明:

④配置TL0与TH0寄存器

为了使其每隔一毫秒产生一次中断,将计数器的初始值调整,由原来的从0开始到溢出(大于65535)调整为需要的初始值到溢出。

这样就能实现在需要的时间内产生一次中断,而不是走完65535×单位时间段(单位时间段由上节课的时钟晶振分屏后有关)

配置初始值:

这里将TH0=64535/256,是因为上节讲过,TH0是高位的一个字节,而64535是两个字节,通过C语言的运算符“/”,使得除以256(一个字节长对应的十进制数),可以将低位字节去掉,只保留高位字节(即相除取整,舍弃后面不能整除的低字节内容)。

同理将TL0=64535%256,利用C语言的运算符“%”,将高字节的内容舍弃。(即取余,舍弃能整除的高字节部分,保留不能整除的低字节内容)。

最终使得从64535到65535的距离为1000,根据上节分屏后每1us计数一次(这里是up主的单片机频率为12MHZ分屏得出的1us,本单片机频率为11.0592,不一定适用),1000us相当于1ms,于是就达成了1ms产生一次中断的目的。(产生中断后可以通过处理中断函数的内容,再将时间延长)

下面是截图自up主的说明内容:

最后一行就是利用十进制的处理,而赋初始值的这里则是对16进制的处理(相当于100被替换为256)。

Ps:

①一个字节长为0000 0000,即八位的二进制数。

②这里对TH0与TL0是采用十进制(__)给其赋值,也可用十六进制(0x__)或者八进制(0__)赋值,但最终都会转化为二进制进行处理。

⑤配置中断部分的寄存器

利用上节的图,打通需要的电路,对应线路赋值为1即可。

配置对应的寄存器:

将ET0=1,EA=1,打通IE部分的电路;然后将PT0赋值0(也可不赋值,默认为0),选择低优先级。

⑥在主函数中调用

Ⅲ、编写中断时调用的函数

①编写中断函数模板

编写代码模块:

上图在interrupt 1后面加分号,是因为那是声明,这里为定义,无需加分号。

Ps:

①前面的void Timer0_Routine( )相当于我们自定义的函数(也就是说,函数名字可以改),只是加上了interrupt后,升华成为中断函数而已。

如下图:

②但是即使改动了void,也不能让其成为有返回值的函数,也不能加入参数,否则会出错。

(也就是说,即使是标明了是int类型,但是也不能添加return,否则就会出错)

(可以用int欺骗自己,但其实本质还是void)

如下图:

②验证中断函数是否起作用

利用P2_0=0;放入中断函数中,烧录程序后,发现即使主函数没有调用中断函数,依然能使灯点亮,说明中断起作用了。

③添加中断函数内容,增长内容实现的间隔时间

通过利用变量T0Count计数的方法,将每次执行任务的间隔时间延长,使得原本只有65535us上限的中断函数执行内容,延长至1s执行下一次任务。

(即1ms产生一次中断,计数一次,当计数达1000,即1s后,再执行需要执行的任务)

烧录后,发现灯确实以1s间隔闪烁,说明调整成功。

补充:调整配置寄存器的子函数

①实现在不可位寻址的寄存器中,不改动其他内容的情况下,对需要更改的内容进行调整

改动:将原本TMOD直接赋值改为运用按位与(&)和按位或(|)符号,使得在不改动TMOD高四位的情况下,对低四位进行调整。

原因:因为TMOD是不可位寻址寄存器,当整体赋值时,容易影响到其他的定时器,因此通过按位的方式,实现不改动原来定时器状态的同时,将需要更改的定时器进行调整。

(按位与或的运算口诀:按位与&——全1为1,有0置0; 按位或|——全0为0,有1置1。)

截自up主:

②通过STC烧录软件,生成定时器计数器的初始函数

操作步骤:(下面步骤每次需要生成时都需要进行配置)

(1)点击[定时器计算器];

(2)在[系统频率]中选择自己时钟上对应的晶振频率(这里跟up主不同,为11.0592MHZ);

(3)在[选择定时器]中选择自己需要的定时器(这里为定时器0)

(4)在[定时长度]中选择需要的长度(这里需要1ms)

Ps:如果超出65535us最大计数上限的话,无法生成,因此才需要上面的方法进行延长时间。

(5)在[定时器模式]中选择需要模式(这里为16位)

Ps:这里指的是之前说的定时器/计算器模式。

(6)在定[时器时钟]选择需要的分屏(这里为12T,如果要进行6T分屏,在12T基础上则需要勾选左边的选项,因为这里没法进行定时器时钟选择)

(7)将代码复制到文件中

这里红色划线部分,是新版单片机配置模式,老版本没有,因此需要删除,而两蓝框部分的功能是一样的,可见生成的代码没有中断寄存器配置。

(8)完善生成的代码

补充:之前自行写入的配置代码与生成的代码对比

之前自行写入的配置代码,与生成代码存在1us的差别,原因在初始化中。

生成的代码:

自行写入的配置代码:

利用计算器,可以计数出

64535/256=252,即十六进制的FC,与生成的代码相同。

而64535%256=23,即十六进制的17,比生成的代码少1。

原因:因为溢出是大于65535,即65536才出现溢出,因此如果需要精确的话,那么就需要加上1,或者直接改为64536%256。

如:

因此,我们以后可以采用生成的代码进行编写。

Ⅳ、将定时器函数进行模块化

①编写Timer0.c文件

将之前主函数中的定义内容剪切到这里,然后将定时器中断函数复制粘贴过来,删除掉if语句里面的执行任务功能语句。

这里将中断函数进行注释化,是因为该函数与主函数耦合性比较大(时不时需要用到主函数的不同变量,操作不同,内容不同)。

每次使用中断函数时,只需要复制,粘贴到主函数文件中就行。

②编写Timer0.h文件

③在主函数头文件中调用

Ⅴ、将需要的之前写过的模块化代码拷贝到工程文件中

其中Key为独立按键的模块化代码,Delay为延时函数的模块化代码。

Key.c:

Delay.c

验证Key代码是否正确:(之前没有模块化独立按键的代码)

烧录后,如果实现按下对应按键,对应灯亮起,再按下对应按键熄灭,说明没问题。

Ps:一定要记得边写边测试,否则全部打完,出错后需要找半天。

Ⅵ、编辑主函数文件

①编写主函数独立按键控制部分

里面利用变量LEDMode的值,对LED的方向进行控制。

加入判断语句,使得LEDMode的值只能在0和1之间变化。(可以有其他想法进行优化,比如利用正负数之类,毕竟0和1只是用来代表方向的两个数字,可以用其他数字代替)

补充:利用INTRINS.H头文件中的函数

(1)包含头文件INTRINS.H。

(2)右击该头文件,进入其内部定义。

可见里面有很多功能的函数。

利用划线部分的函数进行编写下面的流水灯部分。

函数1为循环右移,函数2为循环左移;

第一个参数为需要移位的内容,第二个参数为移位位数。

与普通移位区别:

普通移位当到达最高位时,再移位会将数字移出;

而循环移位函数,在移到最高位时,在移位会重新放到最低位,不会移出数字。

无需越界判断,更加方便。

②编写中断函数流水灯部分

Ⅶ、烧录程序

烧录后,即可完成目标效果。

代码二:

实现效果:实现液晶屏中显示时分秒,并按照时间的进位加数。

Ⅰ、新建工程与main.c文件

Ⅱ、添加需要的模块化文件到工程目录下

LCD1602为液晶屏模块化代码,Delay为延时模块化代码,Timer0为定时器模块化代码。

Ⅲ、编译主函数文件

显示时分秒部分:

计时加数部分:

Ps:

之所以不在中断函数中写入LCD_ShowNum函数,是因为该函数的运行时间比较长,而中断函数最好不要写入太长的内容,因此将其放到主函数部分。

8-1、串口通信

串口介绍:

不严格的话,可以说UART就是串口。

电脑与单片机进行通讯

电脑可以通过USB转串口与单片机进行通讯。

USB转串口:

在通讯时,需要利用串口助手进行通讯。

串口助手在网上可以找,也可以选择自己编写(如果有能力的话)。

下面是STC自带的串口助手:

在使用串口时,需要对好相应的串口位(即左上方的串口号要与串口助手划线地方的串口要保持一致,不然无法起作用)

Ps:一般STC里是默认匹配的。

补充小知识:

①电脑的转串口

作用:通过这个东西,实现电脑与单片机通信。

②陀螺仪传感器

作用:能检测当前模块所在的姿态角(比如X、Y轴的姿态角),通过串口将测得的姿态信息发送给单片机(也就是说,它不是串口,是相当于电脑一样的,可以跟单片机通讯的东西),使得单片机也具备测姿态角的能力。——体现串口通讯能增强单片机系统的硬件实力。

③蓝牙串口

作用:可以将数据通过串口发送给蓝牙串口,蓝牙串口就会自动把数据发送到连接该蓝牙的设备(比如手机)——不过设备需要装载app(相当于上面提到的串口助手一样的作用),然后就可以实现设备与单片机通讯。

串口连接

一些基本知识

①简单双向串口通信有两根通信线(发送端TXD和接收端RXD)。

②其中TXD与RXD要交叉连接。

(延长线不需要交叉,因为它只需要延长即可;但一旦通讯,必须交叉,因为必须实现同一时间仅有一方发送,另一方接收)

③当只需单向的数据传输时,可以直接一根通信线。

(因为不存在同时发送的问题,一根线即可完成一方发送,另一方接收)

④当电平标准不一致时,需要加电平转换芯片。

(因为电平不一样的时候,直接接容易因为电流过大导致物件烧坏)

连接图(简要版):

如果设备是独立供电,那么VCC可以不连;如果不是,那么就相连提供电源。

电平标准

电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系。

串口常用的电平标准有如下三种:

TTL电平(晶体管—晶体管逻辑电平):+5V表示1,0V表示0。——单片机使用的电平。

RS232电平:-3~-15V表示1,+3~+15V表示0。

RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)。

Ps:

①差分信号指的是利用两线电压的差值衡量电平,而不是单纯的相对地面的电压(即对地压差),这样使得需要两根线来进行通讯。——USB使用的就是差分信号。

(上面TTL与RS232就是单纯固定一条线为GND=0,这里GND为地面电压,根据另一条线的电压决定其电平,因此通讯时只需要一根线)

②利用差分信号,可以使得RS485电平的传输距离达到一千多米(而TTL电平与RS232仅能传输十多米),提高容错率。

③RS232电平一般用于电脑这种高电压的传输,因为其容忍的变化范围大,稳定性更好。

补充:下面的使用便是RS232电平或RS485电平。

补充:接口及引脚定义

下图为DB9接口(串口的标准接口,传输数据)——9个针:

VGA接口(传输视频,不是串口)——15个针:

虽然外观不同,但二者并不相同,后者不是串口(串行接口)。

DB9的引脚定义

这里可见除了RXD、TXD这两个通讯线,SG这个信号接地线(GND)外,多出来数据准备好,请求发送,清除发送等几根线,这些线是用于流控制,使得在一方数据没有准备好(比如没有空间)时,能延缓数据发送,直到准备好后才接收或发送数据。——51单片机不支持流控制。

常见通信接口比较

相关接口

①单片机内部使用的接口为URAT。

Ps:点对点通讯指的是一方发出信号,仅有一方接收信号;而挂载多个设备则是指一方发出信号,可有多方接收信号。(不管如何,都只能有一方发出信号,否则会出现信号混乱)

如上图,可以一线挂载多个设备进行发送信号,但一次只能一方发出信号。

②单片机上的24C02(用于存储数据的芯片)依靠接口I2C(2为平方)进行单片机的写入与读出。

③单片机上的DS1302的通讯协议与SPI很相似(但不是标准的SPI)。

④单片机上的DS18B20温度传感器使用的就是1-Wire(单引线)。

⑤CAN总线接口一般应用于汽车领域(利用差分信号),利用一根总线挂起各种传感器。

⑥USB接口就是我们日常生活见到的,用于电脑使用的接口。

相关术语

①——————————————

全双工:通信双方可以在同一时刻互相传输数据

(利用两根线,实现同一时刻双方发送数据)

半双工:通信双方可以互相传输数据,但必须分时复用一根数据线

(利用一根线,一方发出去,另一方收,这样同一时刻只能有一方发送数据)

单工:通信只能有一方发送到另一方,不能反向传输

(例如遥控器的通讯,只能一方发送)

②————————————————

异步:通信双方各自约定通信速率

(即双方约定一个时间,使得一方发出时,另一方以一定的时间间隔接收)

如下面发送方以1s的间隔发送数据,而接收方接收的时间间隔不同,接收数据也会不同。

就像下面1s发送的10,因为0.5秒接收一次,所以1被读取了两次,0也被读取了两次,变成了1100。

同步:通信双方靠一根时钟线来约定通信速率

(直接多引一根线,无需约定时间,当线出现上升沿时就采样一下,完成数据的同步)

如上面的I2C(这里2为平方)与SPI中引脚定义里面,因为是同步,所以多出来SCL与SCLK(两个都是时钟线)。

③————————————————————

总线:连接各个设备的数据传输线路(类似于一条马路,把路边各住户连接起来,使住户可以相互交流)

(存在说法为I2C(这里2为平方)总线、SPI总线、单总线(1-Wire)的说法,因为它们都满足总线的特点——可挂载多个设备。)

(不存在UART总线的说法)

51单片机的UART

其他增强型的单片机UART可能多一些。

其中RXD、TXD与P3_0、P3_1的接口是复用关系。

当操作P3_0、P3_1时,那么就是使用的就是其I/O口(使用时切换);

当操作串口时,用该接口发送数据,因为没有操作P3_0、P3_1,所以默认是串口功能。

下图是转换数据用的连接电路:

串口参数及时序图

①波特率:

之前异步时提到的约定通信速率(传送数据帧)。(还有一种叫比特率,传送的是数据位)

补充:(来自搜索)

波特率:是 码元传输速率 单位,他说明单位时间传输了多少个码元。.

比特率:是信息量传送速率单位,即每秒传输 二进制代码 位数。

这些内容涉及调制解调的概念(也就是数模转换)。

②检验位

在原有的8位后再跟一位,负责校验。

解释:

在STC烧录软件中,存在校验位设置。

当选择奇校验时,发送数据为0000 0011时,会在后面补充1,使得1的个数为奇数,并传输给接收端。

(1)当接收端收到信号为0000 0011 1时,接收正常进行。

(2)当接收端收到信号为0000 0100 1时,因为1的个数不是奇数,因此接收异常,于是

就可以要求发送端进行一些处理,如重发之类。

(3)当接收端收到信号为0000 0101 1时,因为1的个数为奇数,因此接收正常进行。

由此可见,这种方法的排除率还是很低的,但是也有一定功效。(偶校验同理)

③停止位

停止位可以是是1位、1.5位或2位,可以由软件设定。 它一定是逻辑1电平 ,标志着传输一个字符的结束。

④空闲位

空闲位是指从一个字符的停止位结束到下一个字符的起始位开始,表示线路处于空闲状态, 必须由高电平来填充。

⑤停止位与空闲位作用

由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。

因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。

适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

串口模式图

串口内部线路

其中SBUF则是串口数据缓存寄存器,

①当SBUF位于左边时,为发送寄存器(如上图连接TXD的线路),此时对SBUF写入值,它就会自动的发送数据出去TXD。(如非必要,过程可不用理)

②当SBUF位于右边时,为接收寄存器(如上图连接RXD的线路),此时将计算机的内容拿出来,赋予右边的内容,即可拿出。(如非必要,过程可不用理)

③每当发送出去时,会产生TI中断(发送中断);而当接收回来时,会产生RI中断(接收中断)。

④中断产生时,就会进入后面的中断函数部分(去中断逻辑)。

如下图:(类似于定时器和中断系统的连接)

与定时器部分的区别在于,这里使用的是定时器1。

这里RI与TI共用一个线路,因此需要进行判断。(可见上面≥1即可进入后面部分,因此需要区分)

串口相关寄存器

这些为特殊功能寄存器,每一位下面都有一根连线对应。

SCON:控制电路怎么工作。

SBUF:上面讲到的串口数据缓存寄存器。

PCON:电源管理寄存器;前面的SMOD与SMOD0位为控制串口的,后面的部分有关电源控制。

IE:中断使能,与中断控制有关。

IPH与IP:控制中断优先级。(之前放的电路图为旧版的,只有两个优先级,本单片机具有四个优先级,因此需要两个寄存器进行配置)

8-2、串口向电脑发送数据&电脑通过串口控制LED

程序一

实现效果:在通电后,可以通过电脑串口中接收到不断递增的数值。

写入代码

Ⅰ、新建工程及main.c文件

方法如之前一样。

Ⅱ、添加已有的模块化文件进工程目录。

其中Delay为延时函数。

Delay.c:

Ⅲ、配置相关的寄存器

①写入基本函数框架

②SCON寄存器配置

SM0/FE:控制是否检测(即之前的检验位),需要置1,不需要置0。(这里不需要,置0)。

SM0、SM1:共同决定串行口工作模式。其中SM0与上面检验位共用(因此需要置1的模式都打开校验位)。(这里调节为模式一,即赋值0、1)

四种模式:

REN:允许/禁止接收控制位。打开时串口可接收数据,关闭时拒绝接收数据(置1开,置0关)。(串口传输给电脑不需要,置0;电脑传输给串口需要,置1)

ps:也可在单片机不传输给时置1,只要不发出数据即可。

TI:发送中断请求标志位。作用类似于之前定时器的TF0,每次请求完中断后,必须用软件进行复位(即写入代码TI=0)。

RI:接收中断请求标志位。作用类似于之前定时器的TF0,每次请求完中断后,必须用软件进行复位(即写入代码RI=0)。

(TI与RI只需要在产生中断后进行复位操作即可。)

操作:

对上面提到的部分操作,没提到的部分置0即可(这些部分不需要使用)。

代码写入:

③其他寄存器

从IE寄存器往下均为中断有关的寄存器,默认为关闭。(这里不需要使用中断函数,因此不用管就行)

④定时器相关寄存器

因为之前的模式选择中,需要用到寄存器1,所以需要利用之前的定时器寄存器的初始化代码。

之前定时器寄存器的初始化代码:

配置TMOD寄存器:

之前配置为定时器0,这里配置定时器1.

配置定时器1时需要使用八位自动重装模式。

补充:16位计数器&八位自动重装计数器

16位计数器:

这种计数器将两个八位寄存器拼接成一个16位计数器,

但是每次进入中断时都需要给计数器赋初值(否则就从0开始),且赋初值的语句会占用一定时间,会导致运行的时间精度不高。

八位自动重装计数器:

这种计数器将两个八位寄存器分开,一个负责缓存数据(AR,Auto Reload),一个负责每次的计数(CNT,Counter)。

每次从中断离开时就会将CNT的数据缓存到AR中,当进入中断函数时,就会将AR的数据自动装载进CNT,这样就避免了赋初值导致的占用时间,提高精度。

但是缺点为计数范围仅为0~255。(因为少了八位,即一个字节的长度)

代码写入:

补充:自动生成波特率配置函数

首先,打开STC烧录软件,点击[波特率计算器]。

然后根据自己的单片机选择对应系统频率。

(本单片机为11.0592MHZ)

接着选择UART、波特率、数据位(有无开检验位)、波特率发生器(定时器模式)、定时器时钟。——(定时器模式本单片机只能选择8位自动重载,其他模式都不具有)

(这里选择串口1、9600、8位、定时器1的8位自动重载、时钟为12T)

(如果为12MHZ,选择波特率为9600无法正常工作,因为误差很大,因此需要选择4800,并勾选波特率倍速,降低误差)

最后将代码复制到主函数文件中。

然后将两条语句删除,完成配置。

⑤PCON寄存器配置

SMOD:当赋值为1时,通信方式1、2、3的波特率加倍;为0时波特率不加倍。

即如果置1,画圈部分开关打到下面;置零,打到上面。

写入代码:

这里PCON及TL1、TH1、ET1、TR1均从上面补充里面生成的代码粘贴而来。

(因为不需要定时器1的中断函数,因此设置ET1为0,可以对比之前定时器的配置寄存器代码)

总结:如非必要,可以选择自动生成。

Ⅳ、配置主函数内容

①检验前面代码是否有效

写入代码

烧录进单片机后,打开串口助手,配置对应的参数。

这里将波特率设置成跟配置寄存器时的波特率一致(否则会出现接发数据不一致的情况,比如一个数据接成两个之类),

校验位设置为无,

停止位设置为1,

点击[打开串口]。——这里可以勾选[编程完成后自动打开串口],这样编译成功后就会自动打开。

观察接收缓冲区变化

可见接收区疯狂输出11,说明成功。

Ps:

因为存在误差的可能,会导致上面数字可能出错,因此可以加延时。(因为发的速度越慢,波特率越低,通讯越稳定,误差的影响也越小)

②编写目标代码

③烧录后在串口助手中检测,可以看到数字每秒依次递增

(中途可以点击复位按键,从头开始,可以看见串口中重新从00开始)

模块化对应代码

Ⅰ、新建UART.c文件,将代码移植(剪切)过去。

Ⅱ、新建UART.h文件,将模板及声明编写。

Ⅲ、在程序一中验证效果。

烧录后检验发现效果相同,说明模块化完成。(一定要随时检验,避免完成后出错需要检验一堆代码)

程序二

实现效果:在电脑中输入对应的十六进制数,能使LED实现对应状态的灯亮起。

写入代码

Ⅰ、获取工程文件。

将程序一的文件复制一份,更改文件夹名字,打开里面的程序。

Ⅱ、更改配置寄存器的模块化代码

①打开接收控制位(前面提到的REN)

②打开中断电路

电路图:

将IE部分的电路接通,赋值1;IP部分的设置优先级保存默认即可,所以不需要设置。

Ps:这里使用的中断电路不是定时器1的中断(即上面的T1线对应的中断),所以ET1保存为0关闭状态。

Ⅲ、编写中断函数

①写入中断函数模板

中断函数的中断号查询图:

根据上面可知,现在设置的中断函数需要的中断号为interrupt 4;因此在函数后面要加的中断号为interrupt 4。

编写代码:

测试中断函数代码:

烧录程序后,在串口助手的发送缓冲区中输入数字,点击[发送数据],可见灯全部亮起,说明中断函数生效。

编写实现效果代码:

这里P2=SBUF可以在=后面加个取反(~),使得输入的数对应的二进制为1时,对应位置的灯点亮。

Ps:这里加入判断语句,确保检测的是接收中断才执行任务。(因为发送中断与接收中断共用一条电路)

Ⅳ、烧录程序

将该程序烧录后,即可实现目标效果。

效果:

在缓冲区输入十六进制数后,会将对应十六进制数转换为二进制数,并对二进制数的相应位数上的LED灯,为0的点亮;

且会在接收缓冲区中接收到单片机发出的信号(自己写入的值)。

补充:移植对应的接收中断函数模板

将串口中断函数模板放入UART.c文件中,方便以后粘贴使用。

波特率的计算(以UP主的12MHZ晶振频率为例)

串口连接图:

下面为up主的配置寄存器代码:

这里的初始值为0xF3,转换为十进制为243

而243距离溢出的256,相差13,因此每过13个数溢出一次。(类似于定时器的赋初值,到1000溢出一样)

根据之前定时器部分说的,12MHZ在12T(12分屏)的模式下,每1us计数一次,因此每13us产生一次溢出。

因此溢出的频率为1/13us(即上面串口连接图的T1溢出率)

即T1的溢出率为0.07692MHZ。

而如果在上面的SMOD那个部分中选择上面的开关(SMOD赋值1,即选择波特率倍速),那么就是仅除以16,因此可得波特率为0.07692/16。

(不选择波特率倍速的话,就要多除以2)

即波特率为0.00480769MHZ=4807.69HZ。(HZ与MHZ相差10的六次方)

而该波特率与up主设置的4800波特率相近。

而其中的误差,就是上面计算出的(波特率-4800)/4800。

误差计算的结果刚好为0.16%。

手册中计算波特率的方式:

总结:如非必要,可以直接用STC烧录软件进行生成即可。

数据显示模式

HEX模式/十六进制模式/二进制模式:以原始数据的形式显示。

文本模式/字符模式:以原始数据编码后的形式显示。

①当打开文本模式时,可以传输相应的字符(ASCLL码表上具有的)。当接收部分也为文本模式时,会收到对应字符,如果为HEX模式,那么接收的就是ASCLL码表上对应的十六进制数。

②当打开HEX模式时,可以传输对应十六进制数。当接收部分也为HEX模式时,会收到对应的十六进制数字;如果为文本模式,那么收到的就是十六进制数在ASCLL码表上对应的字符。

如果觉得《AutoLeaders控制组——51单片机学习笔记(定时器 串口通信)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。