当前位置: 首页 > news >正文

硬件开发1-51单片机3-串口

UART:通用异步收发器

  • 包含 2 个串口:1 个用于 ISP 下载程序,1 个用于与主机通信
  • 主要信号线:RXD (接收信号线)、TXD (发送信号线)
  • 通信特性:全双工、串行、异步

一、通信方式

1、单工

  • 发送方与接收方是固定的
    • 数据只能 A是发 B是收(固定的)
  • 数据传输通过一根信号线实现
  • 数据传输的方向是固定的单向的

2、半双工(如 I2C)

  • 通信的双方既可以作为发送方,也可以作为接收方
  • 数据传输通过一根信号线实现
  • 数据传输的方向可以是双向,但同一时刻的传输方向呈现单一性
  • 典型例子 I2C
    • A 给 B 发的时候,B 不能给 A 发,B 只能去接收数据

3、全双工(如 UART)

  • 通信的双方既可以作为发送方,也可以作为接收方
  • 数据传输通过两根信号线实现(TXD RXD)
  • 数据的传输在任意时刻都是双向的
  • 例(URT)

        

二、数据传输的顺序

        UART 传输遵循 LSB 优先原则(低位先行),先发低位数据

        数据位置

三、数据传输的形式

1、串行

        通过一根信号线传输,按先后次序逐个 bit 发送

  • 概念:通过一根信号线传输数据,按照先后次序逐个bit逐个bit去发送数据
  • 优缺点:
    • 传输速率慢
    • 硬件成本低,实现简单
    • 传输距离远,抗干扰性好
      • (例RS485 差分)(1km工业级)

2、并行

        通过多根信号线同时传输多个 bit

  • 概念:通过多根信号线同时去传输数据
  • 优缺点:
    • 传输速度快
    • 硬件成本高,实现复杂
    • 传输距离近,抗干扰弱
      • 理论传输距离30m,距离增加容易并行线路间信号偏移,易受电磁波干扰,会造成数据受干扰

3、串口通信时序图:

四、串行传输和并行传输的区别

特性串行(如 UART)并行
传输速率较慢(单线逐个 bit 传输)较快(多线同时传输)
硬件成本低,实现简单高,实现复杂
传输距离远,抗干扰性好(如 RS485 差分)近(通常 30 米内),抗干扰性差
干扰问题较少距离增加后易产生信号偏移和电磁干扰

五、串口通信时序

1、空闲状态为高电平

2、高电平变为低电平(发送低电平信号)代表起始位,准备开始通信

3、发送数据(通常 8bit,遵循 LSB 低位先行原则)

4、发送 1bit 校验位(奇偶校验)

5、发送 1bit 停止位,代表本次通信结束

六、奇偶校验

1、局限性

        无法检测偶数个 bit 出错

2、奇校验

        校验位为 '1',数据位中 '1' 的个数加上校验位 '1' 的总数为奇数时,校验通过

3、偶校验

        校验位为 '0',数据位中 '1' 的个数加上校验位 '0' 的总数为偶数时,校验通过

七、串口通信参数

1、波特率

        bps(bit per second),每秒传输的 bit 数量

        常见值:2400、4800、9600、115200

2、数据位

        通常为 8bit

3、停止位:        

        通常为 1bit

4、校验位

        None(N):无校验

        Even(E):偶校验

        Odd(O):奇校验

        典型参数组合:

                9600, 8, N, 1

                2400, 8, E, 1

                115200, 8, O, 1

八、同步通信与异步通信

通信方式时钟线同步方式
I2C有(SCL)同步
SPI有(SCLK)同步
UART异步

1、同步通信

        双方通过共享时钟线约定通信频率,同步发送 / 接收数据

2、异步通信

        无共享时钟线,通过设置相同波特率实现同步(如 UART 发送和接收端均设置为 2400bps)

九、串口寄存器配置

串口的波特率发生器依赖于定时器 1(Timer1)

1、SCON/PCON 串口控制寄存器

        PCON 寄存器 bit6 置 0:通过 SCON 寄存器中 SM0 和 SM1 指定串口工作方式

        SCON 寄存器 bit6 和 bit7 清 0

        SCON 寄存器 SM1(bit6)置 1,SM0(bit7)清 0:串口工作在 8 位 UART 模式

        SCON 寄存器 REN(bit4)置 1:允许串口接收数据

        SCON 寄存器 TI(bit1):串口 8 位数据发送完毕后硬件自动置 1,需软件清 0(查询用)

        SCON 寄存器 RI(bit0):串口 8 位数据接收完毕后硬件自动置 1,需软件清 0(查询用)

        PCON 寄存器 SMOD(bit7)置 1:波特率加倍

2、定时器寄存器配置

        TMOD(定时器模式选择寄存器):

        高四位清 0(针对定时器 1)

        bit5 置 1,bit4 清 0:定时器 1 工作在 8 位自动重装载模式

        写入定时器初值到 TL1 和 TH1

        TCON 寄存器 bit6 置 1:允许定时器 1 开始计数

3、中断寄存器配置

        IE(中断控制寄存器):

        bit7(EA)置 1:CPU 允许响应所有中断

        bit3(ET1)置 1:允许定时器 1 产生中断

十、练习

题目:

        主机发送指令,从机解析主机发送的指令并获得功能码,根据功能码完成对外设的控制,并回复应答给主机 (功能码01:LED控制 功能码02:数码管控制 功能码03:蜂鸣器控制)

注意点:

1、发送缓冲区模式

        HEX 模式:以十六进制数值(0 - 9, A - F)显示原始字节(Byte)。比如字符 A ,其 ASCII 码是 0x41 ,在 HEX 模式下就显示为 41

        文本模式:将字节直接转换为 ASCII 字符(可打印字符优先)来显示数据。比如字节 ,在文本模式下会显示为字符A.

2、数码管的显示—视觉暂留

        数码管一次只能显示一位数字,若要显示多位数字,就需要利用循环不断刷新来实现。具体来说,就是通过循环依次选中不同的数码管位,然后在该位上显示对应的数字,并且每次显示后稍作延迟,由于人眼存在视觉暂留效应,就会感觉所有数字是同时显示的。

具体实际应用,结合digital.c的内容和main.c的调用去理解

        Digiter_show函数通过while循环对输入的数字n进行处理:每次取n的个位数字m,先清空显示(P0 = 0),然后通过select_bit(t++)选中当前要显示的位,再用select_seg(m)在该位上显示数字m,之后延迟一段时间(delay(100)),最后将n除以 10 去掉已经处理过的个位。这样循环往复,直到n变为 0,从而实现了多位数字的动态显示效果,通过不断刷新各个位来让肉眼看起来是同时显示多位数字。

3、类型转换

  • 网络传输的字节本就是 0~255 的无符号值
  • 但 C 语言的char可能会把大于 127 的值当成负数
  • 强制转换确保了我们用 "无符号视角" 去解读这些字节,和十六进制常量的比较才会正确

0xBB这个值:

  • 作为有符号 char 是 - 69
  • 作为无符号 char 是 187
  • 只有用无符号方式比较,才能正确等于十六进制的0xBB(187)

      代码中的recv_buffer,会将接收到的16进制强制转换成10进制

main.c

#include <reg51.h>
#include <stdio.h>
#include <string.h>
#include "uart.h"
#include "delay.h"
#include "led.h"
#include "digital.h"
#include "time.h"#define DEV_ADDRESS	0x01#define HZ200 	63035	//0x01
#define HZ400 	64285	//0x02
#define HZ600 	64702	//0x03
#define HZ800 	64910	//0x04
#define HZ1000 	65035	//0x05//解析主机发过来的指令,并返回一个功能码
int parse(void)
{int ret = 0;unsigned char sum = 0;int i = 0;if ((unsigned char)recv_buffer[0] == 0xAA && (unsigned char)recv_buffer[6] == 0xBB){if ((unsigned char)recv_buffer[1] == 0x01){for (i = 0; i < 5 ; i++){sum += (unsigned char)recv_buffer[i];}if (sum == (unsigned char)recv_buffer[5]){ret = recv_buffer[2];}}}return ret;
}//根据功能码执行主机下发的控制指令
void do_handler(unsigned int n)
{int i = 0;switch (n){case 1:led_show(recv_buffer[4]);break;case 2:while(1){Digiter_show(recv_buffer[4]); }break;case 3:switch (recv_buffer[4]){case 1:h_z = HZ200;break;case 2:h_z = HZ400;break;case 3:h_z = HZ600;break;case 4:h_z = HZ800;break;case 5:h_z = HZ1000;break;default:break;}Timer0_Init();break;default:break;}
}//从机实现对应功能 并给主机答复
//1.将主机发的内容拷贝到要发送给的数组中,并将功能码改为0x81
//2.判断起始和停止位
//3.判断地址码是否相等,是->将前五位求和->赋值给校验码位
//4.利用数组法发送至主机
void callback(void)
{xdata char send_buffer[10];unsigned char sum = 0;int i = 0;memcpy(send_buffer,recv_buffer,7);send_buffer[2] |= (1 << 7);		//将功能码改成0x81if((unsigned char)send_buffer[0] == 0xAA && (unsigned char)send_buffer[6] == 0xBB){if ((unsigned char)send_buffer == DEV_ADDRESS){for (i = 0; i < 5; i++){sum += send_buffer[i];}send_buffer[5] = sum;}} Uart_SendBuffer(send_buffer,7);
}int main(void)
{int ret = 0;Uart_Init();Led_Init();while (1){if (pos != 0){delay(0xAFF);ret = parse();if ( ret != 0){do_handler(ret);	}if (ret != 0){callback();}pos = 0;}}return 0;
}

uart.c

#include <reg51.h>xdata char recv_buffer[32];
unsigned int pos = 0;// 串口接收服务
void uart_RecvHandler(void) interrupt 4
{if ((SCON & (1 << 0)) == 1){if (pos < 32){recv_buffer[pos++] = SBUF;recv_buffer[pos] = 0;}SCON &= ~(1 << 0);}
}//串口初始化
void Uart_Init(void)
{//将scon寄存器中的bit6和bit7清0SCON &= ~(3 << 6);//串口工作模式选择:SMO:0 SM1:1 代表串口工作在8位UART模式SCON |= (1 << 6);// 允许串口接收数据SCON |= (1 << 4); // 串口波特率加倍PCON &= ~(1 << 6);PCON |= (1 << 7);// TMOD寄存器高四位清0// 定时器1工作在8位自动重装模式TMOD &= ~(0x0F << 4);        TMOD |= (1 << 5);            // 2 ^ 8 - 2 ^ smod * focs/32/bps/12	bps:2400TL1 = 230;			        TH1 = 230;// 允许定时器1开始计数TCON |= (1 << 6);             // 允许CPU响应中断 + 允许串口产生中断IE |= (1 << 7) | (1 << 4);    
}void Uart_SendChar(unsigned char ch)
{SBUF = ch;while ((SCON & (1 << 1)) == 0);SCON &= ~(1 << 1);}void Uart_SendStr(const char *p)
{while (*p){Uart_SendChar(*p++);} 
}void Uart_SendBuffer(const char *p,int len)
{while(len--){Uart_SendChar(*p++);}
}

uart.h

#ifndef UART_H__
#define UART_H__extern void Uart_Init(void);
extern void Uart_SendChar(unsigned char ch);
extern void Uart_SendStr(const char *p);
extern void Uart_SendBuffer(const char *p,int len);
extern xdata char recv_buffer[32];
extern unsigned int pos;#endif

led.c

#include <reg51.h>//灯 初始化
void led_init(void)
{P2 = 0xFF;
}//灯 全亮
void led_allon(void)
{P2 = 0; 
}//灯 全灭
void led_alloff(void)
{P2 = 0xFF;
}//灯 翻转
void led_nor(void)
{P2 = P2 ^ 0xFF;
}//某一位bit 亮
void led_show(unsigned int n)
{P2 = ~n;}

led.h

#ifndef LED_H__
#define LED_H__extern void led_init(void);
extern void led_allon(void);
extern void led_alloff(void);
extern void led_show(unsigned int n);
extern void led_nor(void);#endif

time.c

#include <reg51.h>
#include "led.h"#define HZ200 	63035
#define HZ400 	64285
#define HZ600 	64702
#define HZ800 	64910
#define HZ1000 	65035unsigned int h_z = 0;void Timer0_handler(void) interrupt 1
{TH0 = h_z >> 8;TL0 = h_z;P2 ^= (1 << 1);}void Timer0_Init(void)
{TMOD &= ~(0x0F << 0);TMOD |= (1 << 0);TH0 = h_z >> 8;TL0 = h_z;TCON |= (1 << 4);IE |= (1 << 7) | (1 << 1);}

time.h

#ifndef TIMER_H__
#define TIMER_H__extern unsigned int h_z;
extern void Timer0_Init(void);#endif

delay.c

void delay(unsigned int n)
{while(n--);
}

delay.h

#ifndef DELAY_H__
#define DELAY_H__extern void delay(unsigned int n);#endif

http://www.xdnf.cn/news/1460791.html

相关文章:

  • 三阶Bezier曲线曲率极值及对应的u的计算方法
  • LeetCode 994 腐烂的橘子
  • 【C语言】深入理解指针(4)
  • 【LeetCode热题100道笔记】旋转图像
  • pycharm解释器使用anaconda建立的虚拟环境里面的python,无需系统里面安装python。
  • MySQL复制技术的发展历程
  • Spring启示录
  • 从传统CNN到残差网络:用PyTorch实现更强大的图像分类模型
  • BenTsao本草-中文医学大模型
  • 【算法--链表】61.旋转链表--通俗讲解
  • 【Day 44】Shell-Git版本控制器
  • 【Python】数据可视化之分类图
  • Day2p2 夏暮客的Python之路
  • 数学建模25c
  • [数据结构] 链表
  • 深度学习之第七课卷积神经网络 (CNN)调整学习率
  • MySQL子查询的分类讲解与实战
  • 从基础到实践:Web核心概念与Nginx入门全解析
  • 前端url参数拼接和提取
  • 嵌入式基础 -- I²C 信号与位层规则
  • Swift 解法详解:LeetCode 371《两整数之和》
  • 漏洞绕过方式
  • 从零到一:人工智能应用技术完全学习指南与未来展望
  • ClickHouse 分片、 Distributed 表、副本机制
  • flowable基础入门
  • 【c/c++】深度DFS
  • MATLAB平台实现人口预测和GDP预测
  • 美国教授提出的布鲁姆法,结合AI直击学术科研痛点,写作与创新效率直接翻倍!
  • 漫谈《数字图像处理》之实时美颜技术
  • Java并行计算详解