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】

相关推荐
逼子格5 小时前
【Proteus仿真】定时器控制系列仿真——秒表计数/数码管显示时间
数据库·单片机·嵌入式硬件·51单片机·proteus·定时器·硬件工程师
2401_888423097 小时前
51单片机-按键、蜂鸣器、定时器模块及中断
单片机·嵌入式硬件·51单片机
东亚_劲夫7 小时前
STM32—SPI协议
stm32·单片机·嵌入式硬件
♞沉寂9 小时前
c51串口通信原理及实操
单片机·51单片机·c51
猫头虎9 小时前
2025最新超详细FreeRTOS入门教程:第一章 FreeRTOS移植到STM32
stm32·单片机·嵌入式硬件·机器人·硬件架构·freertos·嵌入式实时数据库
清风66666611 小时前
基于STM32单片机的酒驾检测设计
stm32·单片机·嵌入式硬件·毕业设计·课程设计
曙曙学编程12 小时前
stm32——NVIC,EXIT
c语言·c++·stm32·单片机·嵌入式硬件
今日待办13 小时前
Arduino Nano33 BLESense Rev2【室内空气质量检测语音识别蓝牙调光台灯】
c语言·单片机·嵌入式硬件·mcu·语音识别·ardunio·arduinonano33
不懂机器人13 小时前
51单片机------中断系统
单片机·嵌入式硬件·51单片机