【51单片机通信协议】串口

文章目录

    • 一、硬件通信协议
    • 二、三种通信方式
      • 1.单工通信
      • [2.半双工通信(I2C ------>VCC GND SDA SCL)](#2.半双工通信(I2C ——>VCC GND SDA SCL))
      • [3. 全双工通信](#3. 全双工通信)
    • 三、串口UART
      • [3.1 UART](#3.1 UART)
      • [3.2 UART信号线](#3.2 UART信号线)
      • [3.3 串口传输数据顺序](#3.3 串口传输数据顺序)
      • [3.4 串行传输和并行传输](#3.4 串行传输和并行传输)
      • [3.5 串口的通信时序](#3.5 串口的通信时序)
      • [3.6 同步通信和异步通信](#3.6 同步通信和异步通信)
      • [3.7 串口通信参数](#3.7 串口通信参数)
      • [3.8 三种数字信号的电气接口标准](#3.8 三种数字信号的电气接口标准)
      • [3.9 51单片机串口数据寄存器](#3.9 51单片机串口数据寄存器)
      • [3.10 串口初始化流程](#3.10 串口初始化流程)
    • 四、单片机串口应用示例

此篇文章依旧以HC6800-MS这块开发板为例。本片文章可能涉及之前文章内容,下面是前两篇文章的链接,需要的可以看看:

【初识嵌入式之C51】成为点灯大师

【51单片机】GPIO/中断/定时器/PWM

一、硬件通信协议

在单片机上主要有四种通信协议:

UART、I2C、SPI、CAN

这篇文章主要解释串口UART这种通信协议。

二、三种通信方式

1.单工通信

a. 数据的发送方和接收方是固定的;

b. 数据的传输通过一根信号线完成;

c. 数据传输的方向是固定的,只能由发送方传给接收方。

2.半双工通信(I2C ------>VCC GND SDA SCL)

a. 通信双方既可以作为数据的发送方,也可以作为数据的接收方;

b. 数据传输通过一根信号线完成;

c. 数据传输的方向可以是双向的,但同一时刻数据的传输方向呈单一性。

3. 全双工通信

a. 通信双方既可以作为数据的发送方,也可以作为数据的接收方;

b. 数据传输通过两根信号线完成;

c. 同一时刻数据的传输方向是双向的。

三、串口UART

3.1 UART

Universal Async Receiver/Transmitter 通用异步收发器(串口) 全双工、串行

3.2 UART信号线

VCC、GND、TXD发送数据线、RXD接受数据线

3.3 串口传输数据顺序

串口通信,遵循LSB先行原则,即先发送数据的低位,再发送高位;

3.4 串行传输和并行传输

串行 :通过一根信号线传输数据,按照先后次序逐个bit逐个bit去发送数据;

并行:通过多根信号线同时去传输多个bit数据

串行传输特点 :

(1)传输速率慢(只有一根线逐个bit去传输数据);

(2)硬件成本低、实现简单;

(3)传输距离远,抗干扰能力强(信号线少,干扰小,不存在多根线之间的信号偏移)。

并行传输特点 :

(1)传输速率快(通过多根线同时发送多个bit数据);

(2)硬件成本高,实现复杂;

(3)传输距离近,抗干扰能力弱(一般30米内,信号偏移,电磁波干扰、误差大)。

3.5 串口的通信时序

(1)空闲状态为高电平

(2)发送1bit低电平代表起始位

(3)发送8bit数据位()

(4)发送1bit校验位 低电平/高电平(奇偶校验)

(5)发送1bit高电平代表停止位

校验方法

(1)奇偶校验

奇校验:校验位为"1",若数据位中"1"的个数加上校验位的"1"保持"1"的总个数为奇数个,则代表奇校验通过;

偶校验:校验位为"0",若数据位中"1"的个数加上校验位的"0"保持"1"的总个数为偶数个,则代表偶校验通过;

(2)累加和校验

3.6 同步通信和异步通信

时钟线:约定双方的通信频率。

同步通信 :通信双方有一根共享的时钟信号线来约定通信的频率;

异步通信:通信双方没有时钟信号线来约定通信的频率

波特率 :bit per second,每秒传输的bit数量

常见波特率:2400bps 4800bps 9600bps 115200bps

3.7 串口通信参数

9600 8 N 1

9600:波特率

8:8位数据位

N:None无校验

1:1位停止位

3.8 三种数字信号的电气接口标准

电气特性 电气标准

  1. TTL电平
    1(高电平)
    0(低电平)
  2. RS232电平 负逻辑
    1(高电平):-3V-------15V;
    0(低电平):3V------15V;
  3. RS485电平 差分
    1(高电平):2V-6V
    0(低电平):-2V--6V

3.9 51单片机串口数据寄存器

两个缓冲区名字都叫 SBUF,地址都是 0x99;写 = 发送,读 = 接收,硬件自动区分,不是同一个存储单元。

电脑 USB → CH340 芯片(USB 转 TTL) → 51 单片机 RX 引脚 → 存入 51 的接收 SBUF

51 单片机写SBUF=dat,数据进入发送 SBUF,从 TX 引脚输出 → CH340 转 USB → 电脑接收。

3.10 串口初始化流程

tips:

data:将变量的存储位置放到芯片内部RAM(256byte)

xdata:将变量的存储位置放到芯片外部扩展RAM(64KB)

四、单片机串口应用示例

串口任务

主机(Windows)向从机发送Modbus协议格式指令,从机解析指令,根据指令完成对应功能并向从机回复应答。

主从应答 :

主机:永远是发起通信的一方,拥有对通信的绝对控制从机:无法发起通信,只能根据主机下发的指令完成对应的控制应答:从机完成对应功能后,需要给主机一个回复

TCP/IP应用层:HTTPModbus(CRC校验)

功能码:实现的具体功能

累加和校验

0x01:控制LED灯

0x02:数码管显示

0x03:蜂鸣器控制

0x04:温度采集

主机------>从机:

从机------>主机:

主机------>从机:0x01 0000 0001

从机------>主机:0x81 1000 0001

功能码最高位为数据流向位:0:数据从主机到从机 1:数据从从机到主机。

主函数:

c 复制代码
#include <reg51.h>
#include <string.h>

#include "uart.h"
#include "delay.h"
#include "led.h"
#include "digitaltube.h"
#include "beep.h"
#include "modbus.h"

int main()
{	 
	int ret = 0;

	uart_init();
	led_init();
	timer0_init();

	while(1)
	{
		if (pos != 0)
		{
			delay(0xAFFF);

			ret = parse();
			if (ret != 0)
			{
				do_handler(ret);
			}
			if (ret != 0)
			{
				callback();
			}

			pos = 0;
		}
	}

	return 0;
}

延时:

c 复制代码
#include <reg51.h>  
#include "delay.h"

int delay(unsigned int n)
{
	while(n--)
	{
	}
	return 0;
}

串口:

c 复制代码
#include <reg51.h>
#include "uart.h"

xdata char recv_buff[32];
unsigned int pos = 0;

void uart_recv_handler(void) interrupt 4
{
	if((SCON & (1 << 0)) != 0)
	{
		 if(pos < 32)
		 {
		 	recv_buff[pos++] = SBUF;
			recv_buff[pos] = 0;
		 }
		 SCON &= ~(1 << 0);
	}
}

void uart_init()
{
	//配置串口相关寄存器
	//设置UART工作模式:8位UART波特率可变
	SCON &= ~(3 << 6);
	SCON |= (1 << 6);
	//允许串口收发数据
	SCON |= (1 << 4);
	//PCON寄存器SMOD0清0,SCON寄存器指定串口工作方式
	PCON &= ~(1 << 6);
	//波特率翻倍
	PCON |= (1 << 7);
	
	//配置定时器1相关寄存器
	//配置定时器1工作模式:8位自动重装载
	TMOD &= ~(0x0f << 4); 
	TMOD |= (1 << 5);
	//定时器初值:12MHZ:230 11.0592MHZ:232
	TL1 = 230;
	TH1 = 230;
	//打开定时器
	TCON = (1 << 6);

	//中断开关
	//开启CPU总中断+串口中断
	IE |= (1 << 4)|(1 << 7);
}

//发送单个字符
void uart_sendchar(unsigned int dat)
{
	SBUF = dat;

	while((SCON & (1 << 1)) == 0);

	SCON &= ~(1 << 1);
}

//发送字符串
void uart_sendstr(const char *p)
{
	while(*p)
	{
		uart_sendchar(*p++);
	}
}

//发送指定长度的数据
void uart_send_n_str(const char *p, int n)
{
	while(n--)
	{
		uart_sendchar(*p++);
	}
}

定时器:

c 复制代码
#include <reg51.h>
#include "timer.h"

#define INI_VAL 64535

float f_beep = 200;

float t_beep = 0;
unsigned int cnt = 0;
unsigned int ini_val = 0;

void calcu_val()
{
	t_beep = 1 / f_beep;
	cnt = t_beep / 0.000001;
	ini_val = 65535 - (int)cnt;
}

void timer0_handler(void)	interrupt 1
{
	TL0 = ini_val;
	TH0 = (ini_val >> 8);

	P2 ^= (1 << 1);
}

void timer0_init()
{
	TMOD &= (0xf0 << 0);

	TMOD |= (1 << 0);

//	t_beep = 1 / f_beep;
//	cnt = t_beep / 0.000001;
//	ini_val = 65535 - (int)cnt;
	calcu_val();

	TL0 = ini_val;
	TH0 = (ini_val >> 8);

	IE |= (1 << 1) | (1 << 7);

	TCON |= (1 << 4);
}

modbus:

c 复制代码
#include <reg51.h>
#include <string.h>
#include "modbus.h"
#include "led.h"
#include "digitaltube.h"
#include "beep.h"
#include "uart.h"

#define DEV_ADDRES 0x01

//recv_buff:0xAA 0x01 0x01 0x00 0x42 0xEE 0xBB
unsigned char parse(void)
{
	unsigned char sum = 0;
	int i = 0;
	int ret = 0;

	if((unsigned char)recv_buff[0] == 0xAA && (unsigned char)recv_buff[6] == 0xBB)
	{
		if((unsigned char)recv_buff[1] == DEV_ADDRES)
		{
			for(i = 0; i < 5; ++i)
			{
				sum += recv_buff[i];
			}
			if((unsigned char)recv_buff[5] == sum)
			{
				ret = (unsigned char)recv_buff[2];
			}
		}
	}
	
	return ret;	
}

void do_handler(unsigned char n)
{
	switch(n)
	{
		case 0x01:
			led_on(recv_buff[4]);
			break;
		case 0x02:
			digiter_show(recv_buff[4]);
			break;
		case 0x03:
			beep_on((unsigned char)recv_buff[4]);
			break;
		case 0x04:
			break;
		default:
			break;
	}
}

//recv_buff:0xAA 0x01 0x81 0x00 0x42 0xEE 0xBB
void callback(void)
{
	unsigned char sum = 0;
	int i = 0;
	unsigned char send_buff[10];

	memcpy(send_buff, recv_buff, 7);
	send_buff[2] |= (1 << 7);

	if((unsigned char)send_buff[0] == 0xAA && (unsigned char)send_buff[6] == 0xBB)
	{
		if((unsigned char)send_buff[1] == DEV_ADDRES)
		{
			for(i = 0; i < 5; ++i)
			{
				sum += send_buff[i];
			}
			send_buff[5] = sum;
//			if((unsigned char)send_buff[5] == sum)
//			{
//				uart_send_n_str(send_buff, 7);	
//			}
		}
	}
	uart_send_n_str(send_buff, 7);	
}

led:

c 复制代码
#include <reg51.h>
#include "led.h"

void led_init(void)
{
	P2 = 0xff;
}

void led_all_on()
{
	P2 = 0x00;	
}

void led_all_off()
{
	P2 = 0xff;
}

void led_on(unsigned int n)
{
	P2 = ~n;
}

void led_nor()
{
	P2 ^= 0xff;
}

数码管:

c 复制代码
#include <reg51.h>
#include "digitaltube.h"
#include "delay.h"

int digitaltube_on(unsigned int n, unsigned int num)
{
	P1 &= ~(0xdf << 0);
	P1 |= (1 << (n-1));

	switch(num)
	{
		//0011 1111
		case 0: P0 = 0x3f; break;
		//0000 0110
		case 1: P0 = 0x06; break;
		//0101 1011
		case 2: P0 = 0x5b; break;
		//0100 1111
		case 3: P0 = 0x4f; break;
		//0110 0110
		case 4: P0 = 0x66; break;
		//0110 1101
		case 5: P0 = 0x6d; break;
		//0111 1101
		case 6: P0 = 0x7d; break;
		//0000 0111
		case 7: P0 = 0x07; break;
		//0111 1111
		case 8: P0 = 0x7f; break;
		//0110 1111
		case 9: P0 = 0x6f; break;
	}

	return 0;
}

void digiter_show(unsigned int n)
{
	int i = 1;int tmp = 0;

	while(n)
	{
		tmp = n % 10;
		n /= 10;
		digitaltube_on(i, tmp);
		++i;
		delay(100);
	}
}

蜂鸣器:

c 复制代码
#include <reg51.h>
#include "timer.h"

void beep_on(unsigned char ret)
{
	if(0x01 == ret)
	{
		f_beep = 400;
		calcu_val();
	}else if(0x02 == ret)
	{
		f_beep = 600;
		calcu_val();
	}else if(0x03 == ret)
	{
		f_beep = 800;
		calcu_val();
	}else if(0x04 == ret)
	{
		f_beep = 1000;
		calcu_val();
	}else if(0x05 == ret)
	{
		f_beep = 1200;
		calcu_val();
	}

}
相关推荐
晊晌_h1 小时前
嵌入式从0到精通——51单片机(二)
嵌入式硬件·51单片机
2401_862880822 小时前
UART 通信协议
单片机·51单片机
老当益壮梁奶奶8 小时前
51单片机中断系统详解
c语言·单片机·嵌入式硬件·学习·51单片机
secondyoung17 小时前
I2C通信协议详解
arm开发·驱动开发·stm32·单片机·嵌入式硬件·mcu·51单片机
llilian_161 天前
小切口解决大问题:时序校准场景下的标准时间间隔脉冲信号发生器应用方案
功能测试·单片机·嵌入式硬件·51单片机
llilian_161 天前
时间统一系统 高精度时统设备选购避坑指南 授时系统
大数据·网络·人工智能·功能测试·单片机·嵌入式硬件·51单片机
llilian_161 天前
标准时间间隔发生器应用解决方案 脉冲发生器 时间测量仪
大数据·网络·人工智能·功能测试·单片机·嵌入式硬件·51单片机
HRTOS1 天前
HRTOS 4.0 DEBUG:面向 8051 实时系统运行状态的轻量级调试组件
单片机·嵌入式硬件·51单片机
昌原的儿子LEO1 天前
【单片机入门】UART 串行异步通信核心考点梳理
linux·单片机·51单片机