目录

STC89C52单片机学习第20节-8-2串口向电脑发送数据电脑通过串口控制LED

STC89C52单片机学习——第20节: [8-2]串口向电脑发送数据&电脑通过串口控制LED

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做!

本文写于:2025.03.15

前言

本次笔记是用来记录我的学习过程,同时把我需要的困难和思考记下来,有助于我的学习,同时也作为一种习惯,可以督促我学习,是一个激励自己的过程,让我们开始51单片机的学习之路。 欢迎大家给我提意见,能给我的嵌入式之旅提供方向和路线,现在作为小白,我就先学习51单片机了,就跟着B站上的江协科技开始学习了. 在这里会记录下江协科技51单片机开发板的配套视频教程所作的实验和学习笔记内容,因为我之前有一个开发板,我大概率会用我的板子模仿着来做.让我们一起加油! 另外为了增强我的学习效果:每次笔记把我不知道或者问题在后面提出来,再下一篇开头作为解答!

开发板说明

本人采用的是慧净的开发板,因为这个板子是我N年前就买的板子,索性就拿来用了。不再另外购买视频中的普中开发板了。 原理图如下 https://i-blog.csdnimg.cn/direct/b859dfd75d3c4933acbf770140703272.png 视频中的都用这个开发板来实现,如果有资源就利用起来。 仔细看了看:开发板的晶振为:11.0592Mhz;12Mhz晶振是用来给CH340G芯片外置晶振; 下图是实物图 https://i-blog.csdnimg.cn/direct/726b14bbdfb84259acb0d0de5c48d6aa.jpeg#pic_center

引用

51单片机入门教程-2020版 程序全程纯手打 从零开始入门 还参考了下图中的书籍: 手把手教你学51单片机(C语言版) https://i-blog.csdnimg.cn/direct/5d4226a4f3034fb6a499a89b09b2dbdd.png STC89C52手册 https://i-blog.csdnimg.cn/direct/546587e5d36c41d1be3d6eafd8607005.png

解答和科普

一、串口通信

IO 口模拟串口通信,让大家了解了串口通信的本质,但是我们的单片机程序却需要不停的检测扫描单片机IO 口收到的数据,大量占用了单片机的运行时间。在单片机内部做一个硬件模块,让它自动接收数据,接收完了,通知我们一下就可以了。 51 单片机的UART 串口的结构由串行口控制寄存器SCON、发送和接收电路三部分构成。STC89C52系列单片机内部集成有一个功能很强的全双工串行通信口,与传统8051单片机的串口完全兼容。设有2个互相独立的接收、发送缓冲器,可以同时发送和接收数据。发送缓冲器只能写入而不能读出,接收缓冲器只能读出而不能入,因而两个缓冲器可以共用一个地址码(99H)。两个缓冲器统称串行通信特殊功能寄存器SBUF。 https://i-blog.csdnimg.cn/direct/0ef24911355b4452a8c012bb50c29664.png https://i-blog.csdnimg.cn/direct/d1cd9df6d494487faa08676b92832241.png https://i-blog.csdnimg.cn/direct/48dcda76747e4b53a03266284f1f8ab1.png https://i-blog.csdnimg.cn/direct/63ea0c55fb7f442e9d81c8040dfdc67a.png https://i-blog.csdnimg.cn/direct/b1dfc637900548048b13f28f8d351a2e.png https://i-blog.csdnimg.cn/direct/9724a01a0bc2473ca66dc90413e74d80.png 模式1 是最常用的,就是我们前边提到的1 位起始位,8 位数据位和1 位停止位。STC89C52 单片机来讲,这个波特率发生器只能由定时器T1 或定时器T2 产生,而不能由定时器T0 产生,这和我们模拟的通信是完全不同的概念。如果用定时器2,需要配置额外的寄存器,默认是使用定时器1 的。 就使用定时器T1 作为波特率发生器来讲解,方式1 下的波特率发生器必须使用定时器T1 的模式2,也就是自动重装载模式, 定时器的重载值计算公式为:TH1 = TL1 = 256 - 晶振值/12 /2/16 /波特率 和波特率有关的还有一个寄存器,是一个电源管理寄存器PCON,他的最高位可以把波特率提高一倍,也就是如果写PCON |= 0x80 以后,计算公式就成了:TH1 = TL1 = 256 - 晶振值/12 /16 /波特率 公式中数字的含义这里解释一下,256 是8 位定时器的溢出值,也就是TL1 的溢出值,晶振值在我们的开发板上就是11059200,12 是说1 个机器周期等于12 个时钟周期,值得关注的是这个16,我们来重点说明。在IO 口模拟串口通信接收数据的时候,采集的是这一位数据的中间位置,而实际上串口模块比我们模拟的要复杂和精确一些。他采取的方式是把一位信号采集16 次,其中第7、8、9 次取出来, 这三次中其中两次如果是高电平,那么就认定这一位数据是1,如果两次是低电平,那么就认定这一位是0,这样一旦受到意外干扰读错一次数据,也依然可以保证最终数据的正确性。 https://i-blog.csdnimg.cn/direct/97575d14988346f48843ebe02996a30d.png https://i-blog.csdnimg.cn/direct/9bd5b08ffa564ba397b71bcb5ea6a937.png https://i-blog.csdnimg.cn/direct/0ceacbe822c14ec88df514321056774f.png https://i-blog.csdnimg.cn/direct/06e59c4870dc46f9bebba29c31273add.png https://i-blog.csdnimg.cn/direct/91b6fe941a524ad280ed2507d250f92a.png https://i-blog.csdnimg.cn/direct/a88604bb95eb4f448e028e44cddf0a7b.png https://i-blog.csdnimg.cn/direct/8bb4862689b745f68d768c6bd96db7cf.png https://i-blog.csdnimg.cn/direct/133c167c8c4f4241807820aa9b274ecc.png UART 串口程序 一般情况下,我们编写串口通信程序的基本步骤如下所示: 1、配置串口为模式1。 2、配置定时器T1 为模式2,即自动重装模式。 3、根据波特率计算TH1 和TL1 的初值,如果有需要可以使用PCON 进行波特率加倍。 4、打开定时器控制寄存器TR1,让定时器跑起来。 这里还要特别注意一下,就是在使用T1 做波特率发生器的时候,千万不要再使能T1 的中断了。 https://i-blog.csdnimg.cn/direct/58fbcd17f89741109bd72a985e0ec78d.png https://i-blog.csdnimg.cn/direct/27b28bc6f71c4a30ab89b6fce4b5bb8a.png https://i-blog.csdnimg.cn/direct/2121dd5a3b70400884f568388a95e5da.png https://i-blog.csdnimg.cn/direct/8fec714a18b74444b965e3bf516639ce.png TL1 = 0xF3; //设定定时初值 256-243=13 13us溢出一次 1/13us =0.07692MhzTH1 = 0xF3; //设定定时器重装值 256-243=13 SMOD=1 0.07692/16=0.00480769MHZ 1000 1000=4807.69HZ 7.69/4800=0.001602的误差。 https://i-blog.csdnimg.cn/direct/bc937b7f5fb44116b202c6c4a2c5a255.png https://i-blog.csdnimg.cn/direct/d1ad3b547e2e4a4fbe84e1e409ce00fb.png

二、串口向电脑发送数据

配置UART串口: 1、配置串口为模式1。 https://i-blog.csdnimg.cn/direct/c4d5bcc703d442a2be369332a5d332ab.png SCON=0x40; //工作模式选择1 https://i-blog.csdnimg.cn/direct/a272ac6331eb4101a4fc554f386caa06.png 只改变PCON寄存器的最高位,使SMOD为1.给1的时候是不处于2的。所以我们要给1.也就是12个周期的。 PCON &= 0x7F; //波特率不倍速 2、配置定时器T1 为模式2,即自动重装模式。 https://i-blog.csdnimg.cn/direct/00e6b4a112404dfeba30a13293ecc06d.png https://i-blog.csdnimg.cn/direct/a4d5c6465aad458d84440fac97730463.png 只操作T1,左边的M1和M0配置。定时器1应该配置为0010. TMOD &= 0x0F; //设置定时器模式清零 TMOD |= 0x20; //设置定时器模式置1 3、根据波特率计算TH1 和TL1 的初值,如果有需要可以使用PCON 进行波特率加倍。 TL1 = 0xFD; //设定定时初值 TH1 = 0xFD; //设定定时器重装值 4、打开定时器控制寄存器TR1,让定时器跑起来。 这里还要特别注意一下,就是在使用T1 做波特率发生器的时候,千万不要再使能T1 的中断了。 ET1 = 0; //禁止定时器1中断 TR1 = 1; //启动定时器1 https://i-blog.csdnimg.cn/direct/88aec3a3acd14c1daa8d1f72a08a4ae9.png https://i-blog.csdnimg.cn/direct/ccd9991ec3174671a7b13c6338a64976.png 只发给电脑不接受的代码 #include /**

  • @brief 串口初始化
  • @param 无
  • @retval 无 */ void UART_Init(void) //9600bps@11.0592MHz { PCON &= 0x7F; //波特率不倍速 SCON = 0x40; //8位数据,可变波特率 TMOD &= 0x0F; //清除定时器1模式位 TMOD |= 0x20; //设定定时器1为8位自动重装方式 TL1 = 0xFD; //设定定时初值 TH1 = 0xFD; //设定定时器重装值 ET1 = 0; //禁止定时器1中断 TR1 = 1; //启动定时器1 } void UART_SendByte(unsigned char Byte) { SBUF=Byte; while(TI==0); TI=0; main.c #include #include #include “Delay.h” #include “UART.h” unsigned char sec; void main() { UART_Init(); while(1) { UART_SendByte(sec); sec++; Delay(1000); } } 实验现象: https://i-blog.csdnimg.cn/direct/bfa481c388534c9f9ac30524c5e8789b.png

三、电脑通过串口控制LED(*接收和发送)

单片机接收的时候是不知道什么时候电脑会发送,所以用中断来触发。 https://i-blog.csdnimg.cn/direct/043a15c611f84717958032e6e6bd7fde.png SCON = 0x50; //8位数据,可变波特率允许接收REN https://i-blog.csdnimg.cn/direct/3ed4f944aa9e47a4bd12b1504973b95c.png 使能中断 EA=1; ES=1; //接收和发送都会触发中断 https://i-blog.csdnimg.cn/direct/a6479a1c6c3a4a729eb77519492c27d3.png 前面的名称可以自己写 https://i-blog.csdnimg.cn/direct/6539ded051b549718ea921d70dc58e3a.png https://i-blog.csdnimg.cn/direct/2d60ff2c3acd47a9ba29f90ab7a9ca46.png 验证是否进入中断: void UART_Routine() interrupt 4 { P1=0x00; } void UART_Routine() interrupt 4 //发送和接受进入这同一个中断 { if(RI==1) //区分开是发送还是接收 { P1=SBUF; //读取SBUF的值放在P1直接处理了 RI=0; //必须软件清零,硬件置1 } } 实验现象: 电脑通过串口发送数据控制P1口接收SBUF #include #include #include “Delay.h” #include “UART.h” unsigned char sec; void main() { UART_Init(); while(1) { } } void UART_Routine() interrupt 4 //发送和接受进入这同一个中断 { if(RI==1) //区分开是发送还是接收 { P1=SBUF; //读取SBUF的值放在P1直接处理了 UART_SendByte(SBUF); RI=0; //必须软件清零,硬件置1 } } 实验现象: https://i-blog.csdnimg.cn/direct/d1a30bbf48ea4b7b93282a874f2095fd.png 发送控制单片机LED并给电脑显示 https://i-blog.csdnimg.cn/direct/39b4b53f3ce0468fb6dc04a3e7fe6ae2.png UART_SendByte(0x30); https://i-blog.csdnimg.cn/direct/caca2431330c4225bceb60fda2bc516b.png https://i-blog.csdnimg.cn/direct/f8f8119e8576417b97b0f862b38e4528.png https://i-blog.csdnimg.cn/direct/09781d08e98c41b58c01bd8d5c09e9ac.png

问题

1、就是波特率加不加速 2、就是控制位有点多,脑子有点乱了 3、注意配置是否正确 4、另外涉及到通讯之后和我的拓展坞会卡顿我的鼠标

总结

本节课主要学了了LED闪烁,通过延迟函数的延迟,实现了LED闪烁。