单片机I/O接口及通信
4、单片机I/O接口https://i-blog.csdnimg.cn/direct/45d08812f347496bb7a5dd0ed225be88.png4.1、I/O口的结构与功能I/O口(输入/输出端口)是单片机与外部设备进行数据交换的接口。在8051单片机中,通常有P0、P1、P2、P3四个8位并行I/O端口。[*]结构:
[*]锁存器: 用于存储数据输出。
[*]缓冲器: 用于数据输入。
[*]驱动器: 提供足够的电流来驱动外部设备。
[*]功能:
[*]输入模式: 可以读取外部设备的状态(如按键、传感器等)。
[*]输出模式: 可以控制外部设备(如LED、继电器等)。
4.2、I/O口的编程方法
[*]设置I/O口为输入模式:
[*]对于P0、P1、P2、P3端口,可以通过设置相应的数据(定义)方向寄存器(如P1DIR)来控制每个位是输入还是输出。
[*]设置I/O口为输出模式:
[*]同样,通过设置数据方向寄存器来控制端口的方向。
[*]读取输入:
[*]直接读取I/O口寄存器即可。
[*]写入输出:
[*]直接向I/O口寄存器写入数据即可。
4.3、I/O口的应用实例例子1: 控制一个连接在P1.0的LED亮灭( LED控制)#include <reg51.h>void delay(unsigned int ms) { unsigned int i, j; for (i = 0; i < ms; i++) for (j = 0; j < 123; j++); // 简单的延时函数}void main() { P1 = 0xFF; // 初始化P1口,所有LED熄灭 while (1) { P1_0 = 0; // 点亮LED delay(1000); // 延时 P1_0 = 1; // 熄灭LED delay(1000); // 延时 }}https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
补充:在上面这个例子中的. P1=0xFF. 是如何判断
1.首先要清楚的知道P1口有8位并行端口
2.0为输入,1为输出
3.用二进制000 0000(高位在左,低位在右,(右边➡左边数))来转换,那么你想要转换成什么,就把这8位输入端口,转换成输出端口,也就有了上面的0xFF,而0x只是十六进制的标志例子2: 检测连接在P1.0的按键是否被按下(按键检测)#include <reg51.h>void delay(unsigned int ms) { unsigned int i, j; for (i = 0; i < ms; i++) for (j = 0; j < 123; j++);}void main() { P1 = 0xFF; // 将P1口设置为输入模式,并启用内部上拉电阻 while (1) { if (P1_0 == 0) { // 如果P1.0为低电平,表示按键被按下 delay(20); // 延时消抖 if (P1_0 == 0) { // 再次检测,确保按键确实被按下 while (P1_0 == 0); // 等待按键释放 P1_1 = ~P1_1; // 切换P1.1连接的LED状态 } } }} https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
例子3: 控制一个连接在P1.0的继电器开关(继电器控制)#include <reg51.h>void delay(unsigned int ms) { unsigned int i, j; for (i = 0; i < ms; i++) for (j = 0; j < 123; j++);}void main() { P1 = 0xFF; // 初始化P1口,所有继电器断开 while (1) { P1_0 = 0; // 继电器闭合 delay(5000); // 延时 P1_0 = 1; // 继电器断开 delay(5000); // 延时 }} ``https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
`5、单片机定时器/计数器5.1、定时器/计数器的工作原理定时器/计数器是单片机内部的一个重要模块,它可以用于计时或者计数。在8051单片机中,通常有两个定时器/计数器:定时器/计数器0和定时器/计数器1。5.1.1 工作原理:
[*]定时器模式: 当定时器/计数器被配置为定时器模式时,它会对单片机的内部时钟信号进行计数。当计数达到设定值时,定时器溢出,可以触发中断或改变I/O端口的状态。
[*]计数器模式: 当定时器/计数器被配置为计数器模式时,它会对外部信号(通常是T0或T1引脚上的脉冲)进行计数。
5.2、定时器/计数器的编程方法初始化定时器/计数器:
[*]设置定时器/计数器模式。
[*]设置定时器/计数器的初值。
[*]启用或禁用定时器/计数器。
[*]配置中断(如果需要)。
5.3、定时器/计数器的应用实例例子1: 使用定时器0实现1秒的延时(延时)#include <reg51.h>void Timer0_Init() { TMOD &= 0xF0; // 清除定时器0模式位 TMOD |= 0x01; // 设置定时器0为模式1(16位定时器模式) TH0 = 0xFC; // 设置定时器初值(1秒延时,具体值取决于晶振频率) TL0 = 0x18; ET0 = 1; // 启用定时器0中断 EA = 1; // 启用全局中断 TR0 = 1; // 启动定时器0}void Timer0_ISR() interrupt 1 { TH0 = 0xFC; // 重新加载定时器初值 TL0 = 0x18; // 这里可以执行需要延时的代码}void main() { Timer0_Init(); while (1) { // 主循环代码 }}https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
例子2: 使用定时器1对外部脉冲进行计数(脉冲计数)#include <reg51.h>void Timer1_Init() { TMOD &= 0x0F; // 清除定时器1模式位 TMOD |= 0x10; // 设置定时器1为模式1(16位计数器模式) ET1 = 1; // 启用定时器1中断 EA = 1; // 启用全局中断 TR1 = 1; // 启动定时器1}void Timer1_ISR() interrupt 3 { // 这里可以读取TL1和TH1的值,以获取脉冲计数 // 注意:在中断服务程序中,通常不进行复杂操作}void main() { Timer1_Init(); while (1) { // 主循环代码 }} https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
例子3: 使用定时器0产生PWM信号(PWM输出)#include <reg51.h>void Timer0_Init() { TMOD &= 0xF0; // 清除定时器0模式位 TMOD |= 0x02; // 设置定时器0为模式2(8位自动重装载模式) TH0 = 0xFF; // 设置PWM周期(具体值取决于PWM频率) TL0 = TH0; // 初始化TL0 ET0 = 1; // 启用定时器0中断 EA = 1; // 启用全局中断 TR0 = 1; // 启动定时器0}void Timer0_ISR() interrupt 1 { static unsigned char pwm_width = 0; // PWM占空比变量 if (TF0) { // 检查定时器是否溢出 TR0 = 0; // 停止定时器 TH0 = 0xFF; // 重新加载PWM周期 TL0 = TH0; P1_1 = 1; // 开始PWM周期 TR0 = 1; // 重新启动定时器 } else if (TL0 == pwm_width) { P1_1 = 0; // 设置PWM占空比 }}void main() { Timer0_Init();https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]25
[*]26
[*]27
6、单片机中断系统6.1中断系统的组成
[*]中断源:中断源是指能够触发中断的事件或信号。中断源可以是硬件事件(如定时器溢出、外部引脚变化)或软件事件(如软件中断指令)。
[*]中断控制器:中断控制器负责管理中断请求,确定中断的优先级,以及选择哪个中断服务程序(ISR)来响应。
[*]中断向量表:中断向量表是一个存储中断服务程序入口地址的表格。当中断发生时,CPU通过中断向量表找到对应的中断服务程序。
[*]中断服务程序(ISR):中断服务程序是一段用于处理特定中断事件的代码。当中断被触发时,CPU会暂停当前任务,跳转到ISR执行。
6.2中断处理流程
[*]中断请求:中断源发出中断请求信号。
[*]中断识别:中断控制器识别中断请求,并判断其优先级。
[*]中断响应:如果中断被允许,CPU会暂停当前任务,保存当前程序状态(如程序计数器、寄存器等),然后跳转到对应的中断服务程序。
[*]执行中断服务程序:CPU执行中断服务程序来处理中断事件。
[*]恢复执行:中断服务程序执行完毕后,CPU恢复之前保存的程序状态,并返回到中断发生前的位置继续执行。
6.3中断优先级和嵌套中断系统通常支持中断优先级,以决定多个中断同时发生时哪个中断将被首先处理。中断嵌套是指一个中断服务程序在执行时可以被另一个更高优先级的中断打断。6.4程实践#include <reg51.h>// 外部中断0服务程序void External0_ISR(void) interrupt 0 { // 执行外部中断0的处理代码}// 定时器0中断服务程序void Timer0_ISR(void) interrupt 1 { // 执行定时器0的处理代码}void main() { EA = 1; // 全局中断使能 EX0 = 1;// 外部中断0使能 ET0 = 1;// 定时器0中断使能 // 其他初始化代码... while(1) { // 主循环代码 }} https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
7、单片机串行通信单片机的串口通信是一种常用的数据传输方式,它允许单片机与其他设备(如计算机、传感器、其他单片机等)进行数据交换。串口通信的基本概念串口通信(Serial Communication)是一种按照位序列进行数据传输的方式,通常使用串行通信接口串口通信的主要参数
[*]波特率(Baud Rate):表示每秒钟传送的位数,单位是bps(bits per second)。
[*]数据位(Data Bits):表示每个数据帧中数据位的数量,通常为7或8位。
[*]停止位(Stop Bits):表示每个数据帧结束时的停止位的数量,通常为1、1.5或2位。
[*]校验位(Parity Bit):用于错误检测的位,可以是奇校验、偶校验或无校验。
[*]流控制(Flow Control):用于防止数据丢失的技术,如硬件流控制(RTS/CTS)或软件流控制(XON/XOFF)。
串口通信的硬件接口
[*]RX(接收):用于接收数据。
[*]TX(发送):用于发送数据。
[*]GND(地):用于信号参考点。
单片机串口通信的步骤
[*]初始化串口:设置波特率、数据位、停止位、校验位等参数。
[*]配置中断(可选):如果使用中断方式进行数据接收和发送,需要配置相关的中断服务程序。
[*]数据发送:编写代码将数据写入串口发送缓冲区。
[*]数据接收:编写代码从串口接收缓冲区读取数据。
示例1:8051单片机串口通信#include <reg51.h>```c```c```bash```bash// 假设使用11.0592MHz的晶振void Serial_Init() { SCON = 0x50;// 设置为模式1,8位数据,可变波特率 TMOD |= 0x20; // 定时器1使用模式2(自动重装载) TH1 = 0xFD; // 设置波特率为9600 TL1 = 0xFD; // 与TH1相同 TR1 = 1; // 启动定时器1 TI = 1; // 设置TI位,准备发送}void Serial_SendByte(unsigned char dat) { SBUF = dat; // 将数据放入发送缓冲区 while (!TI);// 等待发送完成 TI = 0; // 清除发送完成标志}void main() { Serial_Init(); // 初始化串口 while (1) { Serial_SendByte('A'); // 发送字符'A' // 可以添加延时,控制发送速度 }} https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]25
[*]26
[*]27
[*]28
[*]29
[*]30
[*]31
[*]32
[*]33
首先初始化串口,然后在一个无限循环中发送字符’A’。Serial_Init函数设置了串口的工作模式和波特率,而Serial_SendByte函数负责发送一个字节的数据。8、单片机外围设备扩展单片机连接到各种外围设备的详细插图
https://i-blog.csdnimg.cn/direct/3b31050341a142119c83c47329d193c2.png
页:
[1]