一、串行通信与并行通信
1、串行通信
- 定义:数据一位一位地按顺序通过单条传输线进行传输的通信方式。
- 优点:传输线少,成本低,适合长距离传输
- 缺点:传输速度相对较慢
2、并行通信
- 定义:数据的各位同时通过多条并行传输线进行传输的通信方式。
- 优点:传输速度快,一次可以传输多个位
- 缺点:需要多条传输线,成本高,抗干扰能力弱,不适合长距离传输
在 51 单片机中,串口通信属于串行通信,而像 P0 口作为数据总线进行 8 位数据传输时则属于并行通信方式。
二、单工、半双工与全双工通信
1、单工通信
- 定义:数据传输只能在一个方向上进行,不能反向传输。
- 例子:收音机接收广播、打印机接收数据
2、半双工通信
- 定义:数据可以双向传输,但不能同时进行,只能交替进行。
- 特点:双方都能发送和接收数据,但同一时刻只能有一方发送
- 例子:对讲机
3、全双工通信
- 定义:数据可以同时在两个方向上进行传输。
- 特点:双方可以同时发送和接收数据,需要两条独立的传输线
- 例子:电话通信、51 单片机的 UART 串口通信
三、串口通信及其时序
1、定义
串口通信(串行端口通信)是一种通过串行方式(一位接一位)在设备之间传输数据的通信协议。在 51 单片机中,通常指 UART(通用异步收发传输器)通信。
2、串口通信时序
1)空闲状态:通信线路处于高电平状态
2)起始位:发送方发送一个低电平,表示数据传输开始
3)数据位:紧接着起始位之后,是实际传输的数据,可以是 5-8 位,通常使用 8 位
4)校验位(可选):用于数据校验,有奇校验、偶校验、无校验等方式
5)停止位:表示一帧数据传输结束,通常为 1 位、1.5 位或 2 位的高电平
四、串口通信速率及常见波特率
1、定义
串口通信的速率由波特率(Baud Rate) 决定,波特率表示单位时间内传输的位数,单位是 bps(比特每秒)。
2、常见的波特率
- 1200 bps
- 2400 bps
- 4800 bps
- 9600 bps(51 单片机最常用)
- 115200 bps
在实际应用中,通信双方必须使用相同的波特率才能正常通信。
五、同步通信与异步通信
1、同步通信
- 定义:发送方和接收方使用同一个时钟信号来同步数据传输,数据连续传输,传输效率高。
- 特点:需要时钟信号线,数据传输速率高,适用于短距离高速通信
- 例子:SPI 通信、I2C 通信
2、异步通信
- 定义:发送方和接收方使用各自独立的时钟信号,通过起始位和停止位来实现数据同步。
- 特点:不需要时钟信号线,硬件简单,适用于长距离通信
- 例子:UART 串口通信
串口通信属于异步通信,它通过起始位和停止位来标记一帧数据的开始和结束,不需要专门的时钟线。
六、TTL、RS232 与 RS485
1、TTL 电平
- 是单片机内部使用的电平标准
- 逻辑 1:+5V(或 3.3V)
- 逻辑 0:0V
- 传输距离短,一般不超过 1 米
- 51 单片机的串口直接输出的就是 TTL 电平
2、RS232
- 是一种串行通信接口标准
- 逻辑 1:-3V 至 - 15V
- 逻辑 0:+3V 至 + 15V
- 需要通过电平转换芯片(如 MAX232)与 TTL 电平相互转换
- 传输距离相对较短,一般不超过 15 米
- 支持全双工通信
3、RS485
- 是一种差分信号传输的串行通信标准
- 采用差分信号传输,抗干扰能力强
- 支持多点通信,可以连接多个设备
- 传输距离远,可达 1200 米
- 通常工作在半双工模式
- 广泛应用于工业控制领域
在 51 单片机应用中,常通过 MAX232 芯片将 TTL 电平转换为 RS232 电平,或通过 MAX485 芯片转换为 RS485 电平,以满足不同的通信需求。
七、应用示例
1、利用单片机实现不同按键产生不同Hz的声响(电子琴)
cs
#include <reg52.h>
#include "key.h"
#define Hz200 63035
#define Hz400 64285
#define Hz600 64702
#define Hz800 64910
#define Hz1000 65035
unsigned short n = Hz200;
void init_timer0(void)
{
TMOD &= ~(3 << 2);
TMOD &= ~(3 << 0);
TMOD |= (1 << 0);
TH0 = n >> 8;
TL0 = n;
IE |= (1 << 7) | (1 << 1); //中断允许寄存器
}
void timer0_handler(void) interrupt 1
{
P2 ^= (1 << 1);
TH0 = n >> 8;
TL0 = n;
}
int main(void)
{
init_timer0();
init_key();
while(1)
{
int key;
key = key_pressed();
if(key == 1)
{
n = Hz200;
TCON |= (1 << 4);
}
else if(key == 2)
{
n = Hz400;
TCON |= (1 << 4);
}
else if(key == 3)
{
n = Hz600;
TCON |= (1 << 4);
}
else if(key == 4)
{
n = Hz800;
TCON |= (1 << 4);
}
else if(key == 5)
{
n = Hz1000;
TCON |= (1 << 4);
}
else if(key == 0)
{
TCON &= ~(1 << 4);
}
}
return 0;
}
2、打印51单片机中各数据类型的字节长度(int、short、float、char、long、double、指针)
cs
#include <reg52.h>
#include "delay.h"
#include <string.h>
#include <stdio.h>
#include "digiter.h"
void init_uart(void)
{
unsigned char t;
t = SCON; //串行控制寄存器
t &= ~(3 << 6);
t |= (1 << 6) | (1 << 4);
SCON = t;
PCON |= (1 << 7); //SMOD=1
IE |= (1 << 7) | (1 << 4);//2 中断允许寄存器
t = TMOD;
t &= ~(3 << 4);
t |= (2 << 4);
t &= ~(3 << 6);
TMOD = t;
TH1 = 204;
TL1 = 204;
TCON |= (1 << 6);
}
xdata char rcv_buffer[64] = {0};
int pos = 0;
void uart_handle(void) interrupt 4//串口中断
{
if((SCON & (1 << 0)) != 0)
{
rcv_buffer[pos++] = SBUF;
//P2 = SBUF;
SCON &= ~(1 << 0);
}
}
void send_char(char ch)
{
SBUF = ch;
while((SCON & (1 << 1)) == 0);
SCON &= ~(1 << 1);
}
void send_buffer(const char *p, int len)
{
while(len--)
{
send_char(*p++);
}
}
int main(void)
{
xdata char buff[64];
init_uart();
while(1)
{
int n = sizeof(int);
sprintf(buff, "int size = %d\n", n);
send_buffer(buff, strlen(buff));
n = sizeof(char);
sprintf(buff, "char size = %d\n", n);
send_buffer(buff, strlen(buff));
n = sizeof(short);
sprintf(buff, "short size = %d\n", n);
send_buffer(buff, strlen(buff));
n = sizeof(long);
sprintf(buff, "long size = %d\n", n);
send_buffer(buff, strlen(buff));
n = sizeof(float);
sprintf(buff, "float size = %d\n", n);
send_buffer(buff, strlen(buff));
n = sizeof(double);
sprintf(buff, "double size = %d\n", n);
send_buffer(buff, strlen(buff));
n = sizeof(s);
sprintf(buff, "* size = %d\n", n);
send_buffer(buff, strlen(buff));
send_buffer(s, strlen(s));
if(pos != 0)
{
delay(0x9FFF);
pos = 0;
memset(rcv_buffer, 0, sizeof(rcv_buffer));
}
}
return 0;
}
3、实现主从应答模式(主机发送指令,从机发送相对应的语句)
cs
#include <reg52.h>
#include "delay.h"
#include <string.h>
#include <stdio.h>
#include "digiter.h"
#include "key.h"
void init_uart(void)
{
unsigned char t;
t = SCON; //串行控制寄存器
t &= ~(3 << 6);
t |= (1 << 6) | (1 << 4);
SCON = t;
PCON |= (1 << 7); //SMOD=1
IE |= (1 << 7) | (1 << 4);//2 中断允许寄存器 P160
t = TMOD;
t &= ~(3 << 4);
t |= (2 << 4);
t &= ~(3 << 6);
TMOD = t;
TH1 = 204;
TL1 = 204;
TCON |= (1 << 6);
}
xdata char rcv_buffer[64] = {0};
int pos = 0;
void uart_handle(void) interrupt 4//串口中断
{
if((SCON & (1 << 0)) != 0)
{
rcv_buffer[pos++] = SBUF;
//P2 = SBUF;
SCON &= ~(1 << 0);
}
}
void send_char(char ch)
{
SBUF = ch;
while((SCON & (1 << 1)) == 0);
SCON &= ~(1 << 1);
}
void send_buffer(const char *p, int len)
{
while(len--)
{
send_char(*p++);
}
}
int main(void)
{
xdata char buff[64];
init_uart();
while(1)
{
if(pos != 0)
{
delay(0x9FFF);
if(strcmp(rcv_buffer, "China") == 0)
{
send_buffer("OK", 2);
}
else if(strcmp(rcv_buffer, "Hello") == 0)
{
send_buffer("confirm", 7);
}
pos = 0;
memset(rcv_buffer, 0, sizeof(rcv_buffer));
}
}
return 0;
}
4、DS18B20传感器显示温度
1)ds18b20.c
cs
#include <reg52.h>
#include <intrins.h>
#include "delay.h"
#include "ds18b20.h"
static int reset_ds18b20(void)
{
int t;
DS18B20_CLEAR;
Delay10us(70);
DS18B20_SET;
Delay10us(4);
t = 0;
while(DS18B20_TST && t < 30)
{
Delay10us(1);
++t;
}
if(t >= 30)
{
return 0;
}
t = 0;
while( !DS18B20_TST && t < 30)
{
Delay10us(1);
++t;
}
if(t >= 30)
{
return 0;
}
return 1;
}
void ds18b20_write(unsigned char n)
{
int i;
for(i = 0; i < 8; i++)
{
if(n & 0x01) //1
{
DS18B20_CLEAR;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
DS18B20_SET;
Delay10us(5);
}
else
{
DS18B20_CLEAR;
Delay10us(6);
DS18B20_SET;
}
n >>= 1;
}
}
unsigned char ds18b20_read(void)
{
unsigned char ret = 0;
int i;
for(i = 0; i < 8; ++i)
{
DS18B20_CLEAR;
_nop_();
_nop_();
DS18B20_SET;
_nop_();
_nop_();
_nop_();
_nop_();
if(DS18B20_TST)
{
ret |= 1 << i;
}
Delay10us(5);
}
return ret;
}
float get_temp(void)
{
unsigned char tl, th;
short t;
reset_ds18b20();
ds18b20_write(0xCC);
ds18b20_write(0x44);
delay_1ms(750);
reset_ds18b20();
ds18b20_write(0xCC);
ds18b20_write(0xBE);
tl = ds18b20_read();
th = ds18b20_read();
t = tl;
t |= th << 8;
return t * 0.0625;
}
2)uart.c
cs
#include "uart.h"
#include <reg52.h>
xdata char rcv_buffer[64] = {0};
int pos = 0;
void init_uart(void)
{
unsigned char t;
t = SCON; //串行控制寄存器
t &= ~(3 << 6);
t |= (1 << 6) | (1 << 4);
SCON = t;
PCON |= (1 << 7); //SMOD=1
IE |= (1 << 7) | (1 << 4);//2 中断允许寄存器 P160
t = TMOD;
t &= ~(3 << 4);
t |= (2 << 4);
t &= ~(3 << 6);
TMOD = t;
TH1 = 204;
TL1 = 204;
TCON |= (1 << 6);
}
void uart_handle(void) interrupt 4
{
if((SCON & (1 << 0)) != 0)
{
rcv_buffer[pos++] = SBUF;
SCON &= ~(1 << 0);
}
}
void send_char(char ch)
{
SBUF = ch;
while((SCON & (1 << 1)) == 0);
SCON &= ~(1 << 1);
}
void send_buffer(const char *p, int len)
{
while(len--)
{
send_char(*p++);
}
}
3)delay.c
cs
#include "delay.h"
#include <intrins.h>
void delay(unsigned int n) //0~65535
{
while(n--);
}
void Delay10us(unsigned int n)//12MHz
{
unsigned char data i;
_nop_();
_nop_();
_nop_();
i = 2 * n;
while(--i)
{
_nop_();
}
}
void delay_1ms(unsigned int n)
{
while(n--)
{
Delay10us(100);
}
}
4)main.c主函数
cs
#include <reg52.h>
#include <intrins.h>
#include <stdio.h>
#include <string.h>
#include "uart.h"
#include "delay.h"
#include "ds18b20.h"
#define DS18B20_SET (P3 |= (1 << 7))//置位,释放
#define DS18B20_CLEAR (P3 &= ~(1 << 7))
#define DS18B20_TST ((P3 & (1 << 7)) != 0)//检测
int main(void)
{
xdata char s[24];
init_uart();
while(1)
{
float f;
f = get_temp();
sprintf(s, "%f", f);
send_buffer(s, strlen(s));
}
return 0;
}
5、modbus模型(主机通过输入不同的指令组,实现对从机功能的控制)
cs
#include <reg52.h>
#include "delay.h"
#include <string.h>
#include <stdio.h>
#include "digiter.h"
#include "key.h"
#define Hz200 63035
#define Hz400 64285
#define Hz600 64702
#define Hz800 64910
#define Hz1000 65035
void init_uart(void)
{
unsigned char t;
t = SCON; //串行控制寄存器
t &= ~(3 << 6);
t |= (1 << 6) | (1 << 4);
SCON = t;
PCON |= (1 << 7); //SMOD=1
IE |= (1 << 7) | (1 << 4);//2 中断允许寄存器 P160
t = TMOD;
t &= ~(3 << 4);
t |= (2 << 4);
t &= ~(3 << 6);
TMOD = t;
TH1 = 204;
TL1 = 204;
TCON |= (1 << 6);
}
unsigned short n = Hz200;
void init_timer0(void)
{
TMOD &= ~(3 << 2);
TMOD &= ~(3 << 0);
TMOD |= (1 << 0);
TH0 = n >> 8;
TL0 = n;
//TCON |= (1 << 4); //打开定时器
IE |= (1 << 7) | (1 << 1);
}
void timer0_handler(void) interrupt 1
{
P2 ^= (1 << 1);
TH0 = n >> 8;
TL0 = n;
}
void show_Hz(void)
{
int key;
key = key_pressed();
if(key == 1)
{
n = Hz200;
TCON |= (1 << 4);
}
else if(key == 2)
{
n = Hz400;
TCON |= (1 << 4);
}
else if(key == 3)
{
n = Hz600;
TCON |= (1 << 4);
}
else if(key == 4)
{
n = Hz800;
TCON |= (1 << 4);
}
else if(key == 5)
{
n = Hz1000;
TCON |= (1 << 4);
}
else if(key == 0)
{
TCON &= ~(1 << 4);
}
}
xdata char rcv_buffer[64] = {0};
int pos = 0;
int digiter_num = 0;
int display_t = 0;
int dis = 0;
void uart_handle(void) interrupt 4
{
if((SCON & (1 << 0)) != 0)
{
rcv_buffer[pos++] = SBUF;
//P2 = SBUF;
SCON &= ~(1 << 0);
}
}
void send_char(char ch)
{
SBUF = ch;
while((SCON & (1 << 1)) == 0);
SCON &= ~(1 << 1);
}
void send_buffer(const char *p, int len)
{
while(len--)
{
send_char(*p++);
}
}
//校验码
unsigned char sumOfTheArray(unsigned char *p, int len)
{
unsigned char sum = 0;
int i;
for(i = 0; i < len; ++i)
{
sum += p[i];
}
return sum;
}
//工作功能选择
void parse(void)
{
float t;
xdata unsigned char s[12];
unsigned char nub1 = 0;
unsigned char nub2 = 0;
nub1 = (unsigned char)rcv_buffer[3];
nub2 = (unsigned char)rcv_buffer[4];
//起始字节、结束码
if((unsigned char)rcv_buffer[0] == 0xAA && (unsigned char)rcv_buffer[pos - 1] == 0x0D)
{ //设备地址
if((unsigned char)rcv_buffer[1] == 0x01)
{ //校验码
if(sumOfTheArray(rcv_buffer, 7) == (unsigned char)rcv_buffer[7])
{ //功能码
unsigned char order;
order = rcv_buffer[2];
switch(order)
{
case 0x01://亮灯
P2 = nub1;
display_t = 0;
break;
case 0x02://show_num 数码管
digiter_num = (nub1 << 8 | nub2);
display_t = 1;
break;
case 0x03://温度
t = get_temp();
s[0] = 0xAA;
s[1] = 0x01;
s[2] = 0x83;
memcpy(s + 3, &t, sizeof(t));
s[7] = sumOfTheArray(s, 7);
s[8] = 0x0D;
send_buffer(s, 9);
break;
case 0x04://发声
n = Hz200;
TCON |= (1 << 4);
break;
case 0x05:
n = Hz400;
TCON |= (1 << 4);
break;
case 0x06:
n = Hz600;
TCON |= (1 << 4);
break;
case 0x07:
n = Hz800;
TCON |= (1 << 4);
break;
case 0x08:
n = Hz1000;
TCON |= (1 << 4);
break;
case 0x09://实现按键发声
dis = 1;
break;
}
}
}
}
}
int main(void)
{
init_uart();
init_timer0();
init_key();
while(1)
{
if(display_t == 1)
{
show_number(digiter_num);
}
if(dis = 1)
{
show_Hz();
}
pos = 0;
memset(rcv_buffer, 0, sizeof(rcv_buffer));
}
}
return 0;
}
【END】