51单片机---硬件学习(电子琴、主从应答模式、modbus模型、DS18B20传感器显示温度)

一、串行通信与并行通信

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】

相关推荐
无垠的广袤2 小时前
【工业树莓派 CM0 NANO 单板计算机】本地部署 EMQX
linux·python·嵌入式硬件·物联网·树莓派·emqx·工业物联网
雲烟4 小时前
嵌入式设备EMC安规检测参考
网络·单片机·嵌入式硬件
泽虞4 小时前
《STM32单片机开发》p7
笔记·stm32·单片机·嵌入式硬件
田甲4 小时前
【STM32】 数码管驱动
stm32·单片机·嵌入式硬件
up向上up5 小时前
基于51单片机垃圾箱自动分类加料机快递物流分拣器系统设计
单片机·嵌入式硬件·51单片机
资料,小偿14 小时前
4.1.2基于51单片机汇编语言出租车计价器proteus仿真出租车计价器,汇编语言51单片机
汇编·51单片机·proteus
单片机日志15 小时前
【单片机毕业设计】【mcugc-mcu826】基于单片机的智能风扇系统设计
stm32·单片机·嵌入式硬件·毕业设计·智能家居·课程设计·电子信息
松涛和鸣16 小时前
从零开始理解 C 语言函数指针与回调机制
linux·c语言·开发语言·嵌入式硬件·排序算法
小曹要微笑1 天前
STM32F7 时钟树简讲(快速入门)
c语言·stm32·单片机·嵌入式硬件·算法
XINVRY-FPGA1 天前
XCVP1802-2MSILSVC4072 AMD Xilinx Versal Premium Adaptive SoC FPGA
人工智能·嵌入式硬件·fpga开发·数据挖掘·云计算·硬件工程·fpga