51单片机从入门到精通:理论与实践指南常用资源篇(五)
坚持一下,确实还有几天就可以学完了,这段时间的努力和付出都将化为宝贵的成果。正如《人民日报》所说:“每一次努力,都是幸运的伏笔。” 不论是在学习、工作还是生活中,坚持都是通往成功的必经之路。当我们在面对困难和挑战时,能够咬牙坚持下去,往往能够迎来意想不到的收获。
51单片机从入门到精通:理论与实践指南常用资源篇(四)https://blog.csdn.net/speaking_me/article/details/144111747?spm=1001.2014.3001.5501
数码管的静态显示和动态显示
1 数码管的显示原理
数码管是一种可以显示数字和其他信息的电子设备,它由多个发光二极管组成。根据发光二极管的连接方式,数码管可以分为共阴极和共阳极两种类型。共阴极数码管的特点是所有发光二极管的阴极连接在一起形成一个公共端,而共阳极数码管则是所有发光二极管的阳极连接在一起形成公共端。在共阴极数码管中,要使某个段发光,需要在这个段的阳极施加高电平;而在共阳极数码管中,则需要在阴极施加低电平。数码管的显示原理是通过点亮内部的发光二极管来形成数字或其他字符。一个数码管通常由7个或8个发光二极管组成,形成一个“8”字形状,加上一个小数点(DP),可以通过控制这些二极管的亮灭来显示不同的数字或字母。
2 数码管的静态显示
静态显示是指数码管一旦点亮某个数字或字符后,这些段就会持续保持点亮状态,直到新的显示内容被送入数码管为止。在静态显示中,每一位数码管都有独立的段选线和位选线,这样可以直接通过控制位选线来决定点亮哪一位数码管,通过控制段选线来决定点亮哪些段,以显示特定的数字或字符。
例如,若要使数码管显示数字“1”,则需要点亮“b”和“c”段,对于共阴极数码管而言,这意味着需要在“b”和“c”段的阳极施加高电平,而其他段的阳极保持低电平。
3 数码管的动态显示
1 典型数码管显示电路
动态显示是一种利用人眼的视觉暂留效应来实现多位数码管显示的技术。在这种显示方式中,多位数码管的段选线是并联的,而位选线则是独立的。通过快速地循环选择不同的位选线,并在每次选择时向段选线发送正确的显示数据,可以让用户感觉到所有数码管都在同时显示不同的数字或字符。为了实现动态显示,通常会使用74HC573这样的锁存器来帮助管理位选和段选信号,从而有效地减少单片机的I/O口资源消耗。锁存器可以存储数据,确保即使在单片机处理其他任务时,也能保持正确的位选和段选信号,从而保证数码管的正确显示。
2 数码管动态显示编程入门示例
在编程实现数码管的动态显示时,首先需要定义好位选和段选的控制信号,然后通过循环不断地更新每一位数码管的显示内容。下面是一个使用C51单片机实现数码管动态显示的简单示例:
#include <reg52.h> sbit WE = P2^7; // 位选信号的锁存器控制位 sbit DU = P2^6; // 段选信号的锁存器控制位 #define uchar unsigned char #define uint unsigned int uchar code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; void delay(uint z) { unsigned int x,y; for(x = z;x>0;x--) for(y=144;y>0;y--); } void main() { while(1) { P0 = 0xff; // 先关闭所有显示 WE = 1; // 打开位选锁存器 P0 = 0xfe; // 第1个数码管显示 WE = 0; // 关闭位选锁存器 DU = 1; // 打开段选锁存器 P0 = table[0]; // 显示数字0 delay(1); // 延时 // 重复上述过程,依次显示其他数字 } }
4 使用数码管实现24小时时钟
1 任务书
使用数码管实现一个24小时制的电子时钟,能够显示当前的小时、分钟和秒。用户可以通过按键来调整时间,并且时钟应该能够自动递增,模拟真实的时间流逝。
2 典型程序示例及解释
为了实现上述功能,可以利用单片机的定时器中断功能来控制时间的递增,并通过按键输入来调整时间。下面是一个使用C51单片机实现24小时时钟的程序示例:
#include <reg52.h> #define uchar unsigned char #define uint unsigned int uchar code num[10] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; uchar second = 0, minute = 0, hour = 0; void Timer0_Init() { TMOD |= 0x01; // 设置定时器0为模式1 TH0 = (65536 - 50000) / 256; TL0 = (65536 - 50000) % 256; ET0 = 1; // 开启定时器0中断 TR0 = 1; // 启动定时器0 } void Timer0_ISR() interrupt 1 { TH0 = (65536 - 50000) / 256; TL0 = (65536 - 50000) % 256; second++; if (second >= 60) { second = 0; minute++; if (minute >= 60) { minute = 0; hour++; if (hour >= 24) { hour = 0; } } } } void DisplayTime() { uchar disp[4]; disp[0] = num[hour / 10]; disp[1] = num[hour % 10]; disp[2] = num[minute / 10]; disp[3] = num[minute % 10]; // 依次显示小时和分钟 for (uchar i = 0; i < 4; i++) { P0 = disp[i]; P2 = 0x0f & ~(1 << i); // 选择当前位数码管 delay(1); } } void main() { EA = 1; // 开启全局中断 Timer0_Init(); while (1) { DisplayTime(); } }
单片机的串行通信
1 RS-232串行通信的基础知识
1 串行通信标准和串行通信接口
串行通信是一种数据传输方式,其中数据以逐位的形式传输,适用于长距离传输。RS-232是最早的串行通信标准之一,它定义了数据终端设备(DTE)和数据通信设备(DCE)之间的物理连接和电气特性。
2 通信的几个基本概念
串行通信涉及到几个基本概念,包括波特率、数据位、停止位和校验位。波特率决定了每秒钟传输的位数,数据位定义了每次传输的有效数据长度,停止位用于标记数据包的结束,而校验位则用于检测传输过程中可能发生的错误。
3 RS-232串行通信的硬件连接
RS-232接口通常使用9针或25针的D型连接器。最常见的连接方式是使用TXD(发送数据)、RXD(接收数据)和GND(地线)三个引脚。通过这些引脚,单片机可以与其他设备进行数据交换。
4 读写串口数据
在单片机中,可以通过配置串行通信的波特率、数据位、停止位和校验位来设置串行通信接口。读取和发送数据通常通过读写串行通信接口的寄存器来实现。例如,发送数据时,可以将数据写入发送寄存器,接收数据时可以从接收寄存器读取数据。
5 串行控制与状态寄存器
串行通信接口通常包含几个重要的寄存器,如SCON(串行控制寄存器)、SBUF(串行数据缓冲寄存器)和TCON(定时器控制寄存器)。SCON寄存器用于设置串行通信的工作模式和状态,SBUF寄存器用于发送和接收数据,TCON寄存器用于控制定时器中断。
6 串口的工作方式
单片机的串行通信接口支持多种工作模式,包括模式0(同步移位寄存器模式)、模式1(8位UART模式)、模式2(9位UART模式)和模式3(9位UART模式,双倍波特率)。不同的工作模式适用于不同的应用场景,例如模式1常用于普通的异步通信,而模式2和模式3则适用于需要更高波特率或更复杂数据格式的通信。
2 计算机串口通信设置
1 计算机串口通信设置
在计算机上,可以通过串口调试助手软件来配置串口通信参数,如波特率、数据位、停止位和校验位。通过这些设置,可以确保计算机与单片机之间的通信正确无误。
2 单片机串口通信设置
在单片机中,可以通过配置SCON寄存器来设置串行通信的工作模式。例如,设置为模式1时,可以使用以下代码:
void UART_Init() { SCON = 0x50; // 设置为模式1,REN=1 TMOD |= 0x20; // 设置定时器1为模式2(8位自动重装) TH1 = 0xFD; // 设置波特率为9600 TL1 = 0xFD; // 初始化定时器1 TR1 = 1; // 启动定时器1 TI = 1; // 清除发送中断标志 }
3 单片机串口通信的基础程序范例
下面是一个简单的单片机串口通信程序示例,实现了从计算机接收数据并在单片机上显示的功能:
#include <reg52.h> void UART_Init() { SCON = 0x50; // 设置为模式1,REN=1 TMOD |= 0x20; // 设置定时器1为模式2(8位自动重装) TH1 = 0xFD; // 设置波特率为9600 TL1 = 0xFD; // 初始化定时器1 TR1 = 1; // 启动定时器1 TI = 1; // 清除发送中断标志 } void SendChar(char ch) { SBUF = ch; // 发送字符 while (!TI); // 等待发送完成 TI = 0; // 清除发送中断标志 } void main() { UART_Init(); while (1) { if (RI) { // 如果接收到数据 char ch = SBUF; // 读取接收到的数据 RI = 0; // 清除接收中断标志 SendChar(ch); // 发送回接收到的数据 } } }
4 串口通信应用示例(用串口校准时间的数字钟)
通过串口通信,可以实现从计算机校准单片机上的时间。下面是一个简单的示例程序,展示了如何通过串口接收时间数据并更新单片机上的时钟:
#include <reg52.h> #define uchar unsigned char #define uint unsigned int uchar second = 0, minute = 0, hour = 0; void UART_Init() { SCON = 0x50; // 设置为模式1,REN=1 TMOD |= 0x20; // 设置定时器1为模式2(8位自动重装) TH1 = 0xFD; // 设置波特率为9600 TL1 = 0xFD; // 初始化定时器1 TR1 = 1; // 启动定时器1 TI = 1; // 清除发送中断标志 } void Timer0_Init() { TMOD |= 0x01; // 设置定时器0为模式1 TH0 = (65536 - 50000) / 256; TL0 = (65536 - 50000) % 256; ET0 = 1; // 开启定时器0中断 TR0 = 1; // 启动定时器0 } void Timer0_ISR() interrupt 1 { TH0 = (65536 - 50000) / 256; TL0 = (65536 - 50000) % 256; second++; if (second >= 60) { second = 0; minute++; if (minute >= 60) { minute = 0; hour++; if (hour >= 24) { hour = 0; } } } } void SendChar(char ch) { SBUF = ch; // 发送字符 while (!TI); // 等待发送完成 TI = 0; // 清除发送中断标志 } void SetTime() { if (RI) { // 如果接收到数据 char ch = SBUF; // 读取接收到的数据 RI = 0; // 清除接收中断标志 if (ch == 'H') { hour = SBUF; RI = 0; } else if (ch == 'M') { minute = SBUF; RI = 0; } else if (ch == 'S') { second = SBUF; RI = 0; } } } void DisplayTime() { uchar disp[4]; disp[0] = num[hour / 10]; disp[1] = num[hour % 10]; disp[2] = num[minute / 10]; disp[3] = num[minute % 10]; // 依次显示小时和分钟 for (uchar i = 0; i < 4; i++) { P0 = disp[i]; P2 = 0x0f & ~(1 << i); // 选择当前位数码管 delay(1); } } void main() { EA = 1; // 开启全局中断 Timer0_Init(); UART_Init(); while (1) { SetTime(); DisplayTime(); } }
5 单片机与单片机之间的通信
单片机之间也可以通过串行通信接口进行数据交换。通过配置各自的串行通信参数,两台单片机可以互相发送和接收数据,实现协同工作。例如,一台单片机可以作为主控设备,另一台单片机作为从属设备,主控设备通过串口发送命令,从属设备接收命令并执行相应的操作。