51单片机之串口通信、WiFi模块、蓝牙模块、4G模块

2023-05-16

目录

串口通信

全双工通信(打电话)

TTL电平

UART 

字节帧 

串口相关的寄存器

串口的工作模式

蓝牙模块HC-08

HC-08的AT指令​编辑

WiFi模块ESP8266

配置WiFi模块作为客户端连入当前局域网

配置WiFi模块作为服务器

​编辑

4G模块EC03-DNC4

配置4G模块


串口通信

串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方 式的扩展接口。串行接口(Serial Interface)是指数据一位一位地顺序传送。其特点是通信线路简 单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成 本,特别适用于远距离通信,但传送速度较慢

  • 设备之间的一种通信的方式(数据交互)
  • 数据只能一位一位的进行传输
  • 全双工通信
  • 数据传输速度较慢

全双工通信(打电话)

通信允许数据在两个方向上同时传输,它在能力上相当于两个单工通信方式的结合。全双工指可以同时(瞬时)进行信号的双向传输(A→B且B→A)。指A→B的同时B→A,是瞬时同步的。通信允许数据在两个方向上同时传输,它在能力上相当于两个单工通信方式的结合。全双工指可以同时(瞬时)进行信号的双向传输(A→B且B→A)。指A→B的同时B→A,是瞬时同步的。 

TTL电平

TTL是Transistor-Transistor Logic,即晶体管-晶体管逻辑的简称,它是计算机处理器控制的设备 内部各部分之间通信的标准技术。TTL电平信号应用广泛,是因为其数据表示采用二进制规定, +5V等价于逻辑”1”,0V等价于逻辑”0”。

UART 

  • 通用异步收发器(UART)也是一种串口通信协议,通过异步来发送/接收数据,USB转TTL就是使用UART的一种模块。
     
  • 工作原理是将传输数据的每个二进制位一位接一位地传输。在UART通信协议中信号线上的状态为高电平时代表‘1’,信号线上的状态为低电平时代表‘0’。比如使用UART通信协议进行一个字节数据的传输时就是在信号线上产生八个高低电平的组合。
     
  • 两个UART设备之间通信的时候不需要时钟线,这时候就需要在两个UART设备上指定相同的传输速率(波特率),以及数据格式(起始位、数据位、奇偶检验位、停止位),也就是遵循相同的协议。

字节帧 

字符帧也叫数据帧,一帧数据由起始位、数据位、奇偶校验位和停止位组成,对于异步通信,要能够进行数据的正确传送,通信双方必须先约定好传送数据的速率和传送数据的组织格式,即波特率和字符帧的格式。 

  • 起始位:每开始一次通信时发送方先发出一个逻辑”0”的信号(低电平),表示传输字符的开始。
  • 数据位:数据位可以是5、6、7、8,9位等,构成一个字符(一般都是8位)。如ASCII码(7位),扩展BCD码(8位)。先发送最低位,最后发送最高位,使用低电平表示‘0’高电平表示‘1’完成数据位的传输。
  • 奇偶校验位:计算数据位中“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性,校验方式:
  • 停止位:一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。

 总之,使用UART串口协议传输数据时,需要规定双方的传输速率(波特率)一致,数据格式(起始位,数据位,奇偶校验为、停止位)也要保持一致。例如传递字符a时,字符a的一帧信息由起始位、数据位(字符a)、奇偶校验位(可选)、停止位组成。

串口相关的寄存器

串口数据缓冲寄存器(SUBF寄存器)

  • SUBF寄存器有两个缓冲器,分别是只读寄存器和只写寄存器,写SBUF操作完待发送数据的加载,读SBUF操作获得已接收到的数据
  • 想要从SUBF寄存器读取数据时:char data = SBUF;
  • 想要向SUBF寄存器的写入数据时:SBUF = data;

电源控制寄存器PCON


  •  LVDF(B5):低电压检测标志位,同时也是低电压检测中断请求标志位
     
  • GF1、GF0:两个通用工作标志位,用户可以自由使用
     
  • PD:掉电模式设定位,PD=0:单片机处于正常工作状态,PD=1:单片机进入掉电模式可由外部中断或硬件复位模式唤醒,进入掉电模式后,外部晶振停振,CPU、定时器、串行口全部停止工作,只有外部中断工作。在该模式下,只有硬件复位和上电能够唤醒单片机。
     
  •  IDL:空闲模式设定位,IDL=0:单片机处于正常工作状态,IDL=1:单片机进入空闲(Idle)模式,除CPU不工作外,其余仍继续工作,在空闲模式下。

串行控制寄存器SCON

  •  


  • 对于位TI和位RI:

IE寄存器 

IP寄存器、IPH寄存器

串口的工作模式

工作模式1:

  • 完成一帧信息的发送后,硬件置位TI,即TI = 1,向主机请求中断处理。
  • 完成一帧信息的接收后,会判断是否满足RI = 0以及SM2 = 0或接收到的停止位为1这两个条件,如果满足,则这帧信息装入SBUF寄存器,停止位进入SCON寄存器的RB8,然后硬件置位RI,即RI = 1。
  • 波特率可变:

 工作模式2:

  •  完成一帧信息的发送后,硬件置位TI,即TI = 1,向主机请求中断处理。
  • 完成一帧信息的接收后,会判断是否满足RI = 0以及SM2 = 0,接收到的第9位数据位RB8 = 1或SM2 = 1,接收到的第9位数据位RB8 = 1这两个条件,如果满足,则这帧信息装入SBUF寄存器,停止位进入SCON寄存器的RB8,然后硬件置位RI,即RI = 1。
  • 波特率不可变:

 工作模式3:

  •  完成一帧信息的发送后,硬件置位TI,即TI = 1,向主机请求中断处理。
  • 完成一帧信息的接收后,会判断是否满足RI = 0以及SM2 = 0,接收到的第9位数据位RB8 = 1或SM2 = 1,接收到的第9位数据位RB8 = 1这两个条件,如果满足,则这帧信息装入SBUF寄存器,停止位进入SCON寄存器的RB8,然后硬件置位RI,即RI = 1。
  • 波特率可变:

PC机串口调试助手(STC-ISP)发送字符o时让51单片机的蜂鸣器叫,发送字符c时让51单片机的蜂鸣器停止叫。

#include "reg52.h"
#include <intrins.h>

sfr AUXR = 0x8E;

sbit buzzer = P1^2;

char cmd;

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void uartInit()
{
	AUXR = 0x01;
	PCON &= 0x7F;  //配置波特率正常
	SCON = 0x50;  //配置串口选择工作方式1,允许串口接收数据
	
	//配置定时器1为8位自动重装模式
	TMOD &= 0x0F;
	TMOD |= 0x20;
	
	//给定时器1,9600波特率初值
	TH1 = 0xFD;  //定时器1初值
	TL1 = 0xFD;  //定时器1重装值

	ET1 = 0;  //不允许定时器1产生中断
	TR1 = 1;  //开启定时器1

	EA = 1;  //开启总中断
	ES = 1;  //开启串口中断

}

void sendByte(char mydata)
{
	SBUF = mydata;  //向串口发送一帧信息
	while(!TI);  //等待硬件置位
	TI = 0;  //TI软件清0 
}

void sendString(char *str)
{
	while(*str != '\0'){
		sendByte(*str);
		str++;
	}
}

void main()
{
	buzzer = 1;
	uartInit();
	while(1){
		sendString("jiangxiaoya\r\n");  //发送心跳包,确保串口通信没有中断
		Delay1000ms();
	}
}

void myUart() interrupt 4
{
	//接收数据后,RI硬件置位产生的中断
	if(RI){
		RI = 0;  //RI软件清0
		cmd = SBUF;  //获取从pc端接收到的数据

		if(cmd == 'o'){
			buzzer = 0;
		}
		if(cmd == 'c'){
			buzzer = 1;
		}
	}

	//接收数据后,TI硬件置位产生的中断
	if(TI);  
}

PC机串口调试助手(STC-ISP)发送字符串open时让51单片机的蜂鸣器叫,发送字符串close时让51单片机的蜂鸣器停止叫。 

#include "reg52.h"
#include <intrins.h>

sfr AUXR = 0x8E;

sbit buzzer = P1^2;

char cmd[12] ;

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void uartInit()
{
	AUXR = 0x01;
	PCON &= 0x7F;  //配置波特率正常
	SCON = 0x50;  //配置串口选择工作方式1,允许串口接收数据
	
	//配置定时器1为8位自动重装模式
	TMOD &= 0x0F;
	TMOD |= 0x20;
	
	//给定时器1,9600波特率初值
	TH1 = 0xFD;  //定时器1初值
	TL1 = 0xFD;  //定时器1重装值

	ET1 = 0;  //不允许定时器1产生中断
	TR1 = 1;  //开启定时器1

	EA = 1;  //开启总中断
	ES = 1;  //开启串口中断

}

void sendByte(char mydata)
{
	SBUF = mydata;  //向串口发送一帧信息
	while(!TI);  //等待硬件置位
	TI = 0;  //TI软件清0 
}

void sendString(char *str)
{
	while(*str != '\0'){
		sendByte(*str);
		str++;
	}
}

void main()
{
	buzzer = 1;
	uartInit();
	while(1){
		sendString("jiangxiaoya\r\n");  //发送心跳包,确保串口通信没有中断
		Delay1000ms();
	}
}

void myUart() interrupt 4
{
	static int i = 0;

	//接收数据后,RI硬件置位产生的中断
	if(RI){
		RI = 0;  //RI软件清0
		//获取从pc端接收到的数据
		cmd[i] = SBUF;
		i++;
		if(i == 12){
			i = 0;
		}

		//strstr():字符串包含函数,不包含返回NULL
		if(strstr(cmd,"en") != NULL){
			buzzer = 0;
			i = 0;
			memset(cmd,'\0',12);
		}
		if(strstr(cmd,"os") != NULL){
			buzzer = 1;
			i = 0;
			memset(cmd,'\0',12);
		}
	}

	//接收数据后,TI硬件置位产生的中断
	if(TI);  
}

蓝牙模块HC-08

HC-08模块直接接线使用即可,可以使用STC-ISP软件发送AT指令:AT+NAME=名字,来修改蓝牙名字,跟STC-ISP里的串口助手使用方法一样。

HC-08的AT指令

WiFi模块ESP8266

wifi模块通过usb转ttl接入pc端,通过安信可串口调试助手修改esp8266的波特率,让它跟单片机的通信速度保持一致。

连接后发送AT指令修改esp8266波特率:

  •  AT+RST ,重启esp8266
  • AT ,检测esp8266的通信功能是否正常
  • AT+UART=9600,8,1,0,0 ,修改波特率

esp8266的上网模式: 

配置WiFi模块作为客户端连入当前局域网

  • AT+CWMODE=1 ,配置esp8266为客户端
  • AT+CWJAP="WiFi名字","WiFi密码" ,esp8266连接WiFi
  • AT+CIFSR ,查看当前IP地址
     
  • 架设TCP服务器,往期博文《Linux网络编程》有TCP服务器的源码

     
  • AT+CIPSTART="TCP","IP地址",端口号 ,esp8266作为客户端,连入当前IP地址架设的TCP服务器
  • AT+CIPMODE=1 ,开启透传模式
  • AT+CIPSEND ,出现>后可以与服务器互相传输数据
  • +++ ,退出透传模式

上述AT指令对应的响应

用51单片机使用esp8266作为客户端连入服务器

#include "reg52.h"
#include <intrins.h>
#include <string.h>

sfr AUXR = 0x8E;

sbit buzzer = P1^2;

char mybuf[24];

//相关AT指令
char RESET[] = "AT+RST\r\n";  //重启esp8266
code char LJWL[] = "AT+CWJAP=\"haozige\",\"123456789000\"\r\n";  //连接WiFi
code char LJFWQ[] = "AT+CIPSTART=\"TCP\",\"192.168.97.198\",8880\r\n";  //连接TCP服务器
char TCMS[] = "AT+CIPMODE=1\r\n";  //开启透传模式
char SJCS[] = "AT+CIPSEND\r\n";  //开启数据传输

int AT_OK_flag = 0;
int AT_CONNECT_NET_flag = 0;

void Delay500ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 4;
	j = 129;
	k = 119;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Delay5000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 36;
	j = 5;
	k = 211;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void uartInit()
{
	AUXR = 0x01;
	PCON &= 0x7F;  //配置波特率正常
	SCON = 0x50;  //配置串口选择工作方式1,允许串口接收数据
	
	//配置定时器1为8位自动重装模式
	TMOD &= 0x0F;
	TMOD |= 0x20;
	
	//给定时器1,9600波特率初值
	TH1 = 0xFD;  //定时器1初值
	TL1 = 0xFD;  //定时器1重装值

	ET1 = 0;  //不允许定时器1产生中断
	TR1 = 1;  //开启定时器1

	EA = 1;  //开启总中断
	ES = 1;  //开启串口中断

}

void sendByte(char mydata)
{
	SBUF = mydata;  //向串口发送一帧信息
	while(!TI);  //等待硬件置位
	TI = 0;  //TI软件清0 
}

void sendString(char *str)
{
	while(*str != '\0'){
		sendByte(*str);
		str++;
	}
}

void main()
{
	int mark = 0;
	buzzer = 1;

	uartInit();

	Delay5000ms();  //等待esp8266上电
	
	sendString(LJWL);  
	while(!AT_CONNECT_NET_flag);  //等待WiFi连接成功
	//while(!AT_OK);
	AT_OK_flag = 0;
	
	sendString(LJFWQ);
	while(!AT_OK_flag);  //等待esp8266连接TCP服务器
	AT_OK_flag = 0;
	
	sendString(TCMS);
	while(!AT_OK_flag);  //等待esp8266开启透传模式
	AT_OK_flag = 0;
	
	sendString(SJCS);
	while(!AT_OK_flag);  //等待esp8266与tcp开启数据传输

	while(1){
		sendString("jiangxiaoya\r\n");  //发送心跳包,确保串口通信没有中断
		Delay1000ms();
	}
}

void myUart() interrupt 4
{
	static int i = 0;
	char tmp;

	//接收数据后,RI硬件置位产生的中断
	if(RI){
		RI = 0;  //RI软件清0
		//获取从pc端接收到的数据
		tmp = SBUF;

		if(tmp == 'W' || tmp == 'O' || tmp == 'L' || tmp == 'F'){
			i = 0;
		}
		mybuf[i] = tmp;
		i++;

		//连接wifi成功后,esp8266会返回WIFI GT IP
		if(mybuf[0] == 'W' && mybuf[1] == 'I'){
			AT_CONNECT_NET_flag = 1;
			memset(mybuf,'\0',24);
		}

		//esp8266连接TCP服务器或者其他AT指令,esp8266会返回OK
		if(mybuf[0] == 'O' && mybuf[1] == 'K'){
			AT_OK_flag = 1;
			memset(mybuf,'\0',24);
		}

		//TCP服务器发送数据给esp8266的灯控指令
		//开
		if(mybuf[0] == "L" && mybuf[1] == "1"){
			buzzer = 0;
			memset(mybuf,'\0',24);
		}
		//关
		if(mybuf[0] == "L" && mybuf[1] == "2"){	
			buzzer = 1;
			memset(mybuf,'\0',24);
		}

		//WiFi连接失败后,会返回FALL
		if(mybuf[0] == 'F' && mybuf[1] == 'A'){
			
			for(i=0;i<5;i++){
				buzzer = 0;
				Delay500ms();
				buzzer = 1;
				Delay500ms();
			}
			
			sendString(RESET);
			memset(mybuf,'\0',24);
		}

		if(i == 24){
			i = 0;
		}

	}

	//接收数据后,TI硬件置位产生的中断

	if(TI);  
}

配置WiFi模块作为服务器

  • AT+CWMODE=2 ,配置esp8266为服务器
  • AT+CIPMUX=1 ,开启多路连接,允许多个客户端连接,0为单连接
  • AT+CIPSERVER=1 ,开启esp8266服务器(端口号为333)
  • 以该esp8266服务器的IP地址架设客户端,往期博文《Linux网络编程》有TCP客户端的源码
  • AT+CIPSEND=0,4 ,服务器往客户端发送4个字节数据

上述AT指令对应的响应

用51单片机使用esp8266架设服务器

#include "reg52.h"
#include <intrins.h>
#include <string.h>

sfr AUXR = 0x8E;

sbit buzzer = P1^2;

char mybuf[24];

//相关AT指令
char LYMS[] = "AT+CWMODE=2\r\n";  //配置esp8266为路由模式
char DLLJ[] = "AT+CIPMUX=1\r\n";  //配置esp8266多路连接
char JLFWQ[] = "AT+CIPSERVER=1\r\n";  //建立esp8266服务器
char FSSJ[] = "AT+CIPSEND=0,11\r\n";  //向客户端发送数据

char AT_OK_flag = 0;
char AT_CONNECT_NET_flag = 0;
char Client_Connect_Net_flag = 0;

void Delay500ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 4;
	j = 129;
	k = 119;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Delay5000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 36;
	j = 5;
	k = 211;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void uartInit()
{
	AUXR = 0x01;
	PCON &= 0x7F;  //配置波特率正常
	SCON = 0x50;  //配置串口选择工作方式1,允许串口接收数据
	
	//配置定时器1为8位自动重装模式
	TMOD &= 0x0F;
	TMOD |= 0x20;
	
	//给定时器1,9600波特率初值
	TH1 = 0xFD;  //定时器1初值
	TL1 = 0xFD;  //定时器1重装值

	ET1 = 0;  //不允许定时器1产生中断
	TR1 = 1;  //开启定时器1

	EA = 1;  //开启总中断
	ES = 1;  //开启串口中断

}

void sendByte(char mydata)
{
	SBUF = mydata;  //向串口发送一帧信息
	while(!TI);  //等待硬件置位
	TI = 0;  //TI软件清0 
}

void sendString(char *str)
{
	while(*str != '\0'){
		sendByte(*str);
		str++;
	}
}

void main()
{
	int mark = 0;
	buzzer = 1;

	uartInit();

	Delay5000ms();  //等待esp8266上电
	
	sendString(LYMS);  
	while(!AT_OK_flag);  //等待esp8266设置路由模式
	AT_OK_flag = 0;
	
	sendString(DLLJ);
	while(!AT_OK_flag);  //等待esp8266设置多路连接
	AT_OK_flag = 0;
	
	sendString(JLFWQ);
	while(!Client_Connect_Net_flag);  //等待esp8266建立服务器
	AT_OK_flag = 0;

	while(1){
		sendString(FSSJ);  //发送心跳包,确保串口通信没有中断
		Delay1000ms();
		Delay1000ms();
		sendString("jiangxiaoya");
		Delay1000ms();
		Delay1000ms();
	}
}

void myUart() interrupt 4
{
	static int i = 0;
	char tmp;

	//接收数据后,RI硬件置位产生的中断
	if(RI){
		RI = 0;  //RI软件清0
		//获取从pc端接收到的数据
		tmp = SBUF;

		if(tmp == 'W' || tmp == 'O' || tmp == 'L' || tmp == '0'){
			i = 0;
		}
		mybuf[i] = tmp;
		i++;

		//esp8266设置路由模式等其他AT指令,esp8266会返回OK
		if(mybuf[0] == 'O' && mybuf[1] == 'K'){
			AT_OK_flag = 1;
			memset(mybuf,'\0',24);
		}

		//esp8266建立服务器,esp8266会返回0,CONNECT
		if(mybuf[0] == '0' && mybuf[2] == 'C' ){
			Client_Connect_Net_flag = 1;
			memset(mybuf, '\0' , 24);				
		}

		//esp8266服务器发送数据给客户端的灯控指令
		//开
		if(mybuf[0] == "L" && mybuf[1] == "1"){
			buzzer = 0;
			memset(mybuf,'\0',24);
		}
		//关
		if(mybuf[0] == "L" && mybuf[1] == "2"){	
			buzzer = 1;
			memset(mybuf,'\0',24);
		}

		if(i == 24){
			i = 0;
		}

	}

	//接收数据后,TI硬件置位产生的中断

	if(TI);  
}

4G模块EC03-DNC4

配置4G模块

  • 进入AT指令模式:不勾选新行发送指令 +++ 后,勾选新行任意发一条AT指令(不要发AT+REBT,该AT指令为重启4G模块)
  • AT+UARTEX ,查询当前4G模块的波特率
  • AT+UART=9600,NONE ,修改当前当前4G模块的波特率为9600
  • AT+HEARTINFO , 查询当前心跳包的数据
  • AT+HEARTINFO=jiangxiaoya ,修改当前心跳包的数据
  • AT+HEARTM ,查询当前心跳包时间
  • AT+HEARTM=time ,修改当前心跳包的时间,心跳时间为1~65535s,0为关闭心跳包
     
  • 用本地IP地址架设TCP服务器,往期博文《Linux网络编程》有TCP服务器的源码

     
  • 借助花生壳软件,使用刚刚架设的服务器的IP地址和端口号进行内网穿透


     
  • 使用内网穿透映射的地址架设客户端(获取服务器的IP地址和端口号),往期博文《Linux网络编程》有TCP客户端的源码

     
  • 从架设的服务器任意发送一条信息到架设的客户端获取服务器的IP地址和端口号,来供4G模块使用(IP地址:103.46.128.53,端口号:10146)

     
  • AT+SOCK=TCPC,IP地址,端口号 ,连接架设的服务器,连接成功后,4G模块就会往架设的服务器发送心跳包,也就是说,架设的服务器能够与4G模块进行通信,且数据能通过串口交互到pc端的安信可调试助手,即能与单片机进行通信。

 4G模块与51单片机进行通信,发送字符串:open让蜂鸣器叫,发送字符串:close让蜂鸣器不叫

#include "reg52.h"
#include <intrins.h>
#include <string.h>

#define SIZE 12
sfr AUXR = 0x8e;
sbit buzzer = P1 ^ 2;

char cmd[SIZE];

void Delay1000ms() //@11.0592MHz
{
	unsigned char i, j, k;
	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k)
				;
		} while (--j);
	} while (--i);
}

void UartInit(void) // 9600bps@11.0592MHz
{
	PCON &= 0x7F; //波特率不倍速
	SCON = 0x50;  // 8位数据,可变波特率
	AUXR &= 0xBF; //定时器1时钟为Fosc/12,即12T
	AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
	TMOD &= 0x0F; //清除定时器1模式位
	TMOD |= 0x20; //设定定时器1为8位自动重装方式
	TL1 = 0xFD;	  //设定定时初值
	TH1 = 0xFD;	  //设定定时器重装值
	ET1 = 0;	  //禁止定时器1中断
	TR1 = 1;	  //启动定时器1
	EA = 1;		  //允许总中断
	ES = 1;		  //允许串口中断
}

void main()
{
	buzzer = 1;

	UartInit();
	while(1);
}

void Uart_Handler() interrupt 4
{
	static int i = 0; 
	char tmp;
	//接收数据后,RI硬件置位产生的中断
	if(RI){
		RI = 0;  //RI软件清0
		//获取从pc端接收到的数据
		tmp = SBUF;

		if(tmp == ':'){
			i = 0;
		}
		cmd[i++] = tmp;

		if(i == SIZE){
			i = 0;
		}
		
		if(cmd[0] == ':' && cmd[1] == 'o' && cmd[2] == 'p'){
			buzzer = 0;
			i = 0;
			memset(cmd, '\0', SIZE);
		}

		if(cmd[0] == ':' && cmd[1] == 'c' && cmd[2] == 'l'){
			buzzer = 1;
			i = 0;
			memset(cmd, '\0', SIZE);
		}
	}
	if(TI);
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

51单片机之串口通信、WiFi模块、蓝牙模块、4G模块 的相关文章

  • 使用 GitHub Copilot 自动化测试

    代码完成并不是什么新鲜事 像 IntelliSense 这样的工具已经允许开发人员通过尝试自动完成他们正在编写的函数或语句的名称来提高工作效率 xff0c 但是可用的工具只有一定程度的实际 智能 可用 随着 GitHub 的 Copilot
  • 想让你的接口自动化测试更加有效? 这个统计方法必须掌握

    覆盖率概念 接口自动化测试是现代软件开发中不可或缺的一环 xff0c 它能够帮助开发团队自动化执行测试用例 xff0c 以快速而准确地发现并修复软件缺陷 而覆盖率统计则是在测试执行完成后 xff0c 帮助测试团队了解哪些代码路径被覆盖了 x
  • 大小端字节序详解

    目录 引文 大小端介绍 xff08 1 xff09 什么是大端小端 xff08 2 xff09 为什么有大端和小端 xff08 3 xff09 笔试题讲解 引文 在开始正文之前 xff0c 我想先问一下大家 xff0c 内存中是怎样存放一个
  • 【C库函数】strcat函数详解

    目录 strcat 函数原型 参数讲解 返回值详解 函数讲解 xff08 1 xff09 源字符串和目标字符串都必须以 39 0 39 结束 xff08 2 xff09 目标空间必须足够大 xff0c 能容纳下源字符串的内容 xff08 3
  • CAN协议

    CAN xff08 Controller Area Network xff09 是一种常见的串行总线通信协议 xff0c 用于在汽车 工业控制和其他应用中传输数据 它是一种高效 可靠 安全的通信协议 xff0c 具有广泛的应用 下面是CAN
  • 串口协议简介

    串口协议是一种基于串行通信的数据传输协议 它通过串口接口将数据以串行的方式传输 串口协议通常包括物理层 数据链路层和应用层三个部分 xff0c 其中物理层主要定义了串口接口的电气特性 xff0c 数据链路层定义了数据的传输方式和错误检测机制
  • CAN协议总线仲裁原理:数据发送权争夺

    CAN总线仲裁原理是指在多个CAN节点同时发送数据时 xff0c 如何避免冲突 并选择一个节点作为发送者 CAN总线的仲裁原理基于一个分布式仲裁机制 xff0c 它可以快速而可靠地确定哪个节点可以获得总线控制权 xff0c 从而发送数据 C
  • Spring整合JMS(一)——基于ActiveMQ实现

    1 1 JMS简介 JMS的全称是Java Message Service xff0c 即Java消息服务 它主要用于在生产者和消费者之间进行消息传递 xff0c 生产者负责产生消息 xff0c 而消费者负责接收消息 把它应用到实际的业务需
  • getopt函数详解

    getopt 函数是C语言中一个常用的命令行参数解析函数 xff0c 它可以方便地解析命令行输入的参数 xff0c 以便程序对不同参数进行不同的处理 本文将详细讲解getopt 函数的使用方法和注意事项 xff0c 分点阐述如下 xff1a
  • UCOSIII

    UCOSIII简介 xff1a UCOSIII是MicroC OS III的改编版本 xff0c 主要是用于实时系统中的任务调度 xff0c 它是嵌入式系统中应用最广泛的操作系统之一 用函数说明 xff1a 1 OSInit 用于初始化UC
  • UCOSIII-任务创建-库函数

    创建任务 xff1a OSTaskCreate OS TCB amp StartTaskTCB 任务控制块 xff08 amp 传地址 xff09 CPU CHAR 34 start task 34 任务名字 xff08 可以随便写 xff
  • ucosiii-常用api

    uC OS III 提供了许多 API 函数 xff0c 可以根据需要选择使用 以下是一些常用的 uC OS III API 函数 xff1a 任务管理 API OSTaskCreate xff1a 创建一个新任务 xff1b OSTask
  • windows 清除 .git 文件夹

    有时我们需要将 git 管理项目中的 git文件夹删除 xff0c 但是如果项目太多 xff0c 一个一个手动删除太麻烦 xff0c 这时候可以用 bat 批处理文件删除 xff0c 具体操作如下 桌面 右击 新建文本文档 xff0c 此时
  • Your anti-virus program might be impacting your build performance.解决方案

    Your anti virus program might be impacting your build performance 解决方案 在使用 AndroidStudio 时 xff0c 经常会弹出框提示 xff1a Your ant
  • init.rc 启动 shell 脚本 开机执行脚本 init.rc执行shell脚本

    Android 重启时执行 shell 脚本 init rc 执行 shell 脚本 最近有个需求 xff0c 需要生成系统的默认配置 xff0c 使得在系统开机后 xff0c 直接读取已经配置好的文件 当时想的解决方案是 xff0c 在编
  • android 10 自定义系统服务接口给app调用

    Android 安卓自定义系统服务 最近有个需求 xff0c 要增加系统服务 xff0c 生成第三方 jar 包提供给第三方应用调用 xff0c 而且 jar 包必须用特定的包名 xff0c 最后生成的 jar 包不能包含 framewor
  • Android java.lang.NoSuchMethodError: No virtual method ;or its super classes (declaration of

    修改 AOSP 源码后调用错误 java lang NoSuchMethodError No virtual method in class or its super classes declaration of appears in sy
  • 谷歌使用技巧 20 招

    第一招 xff1a 使用搜索栏下方的 Tab 栏 xff0c 可以快速搜索 视频 图片 新闻第二招 xff1a 使用引号 xff0c 默认搜索会去搜索包含输入关键字的结果 xff0c 用 34 holy shit 34 会去进行整句搜索第三
  • 索引算法原理解析(B-tree以及磁盘存储原理)

    刚开始学习的时候 xff0c 百度去查 xff0c 但发现好多说得太复杂不好理解 xff0c 结合各个文章总结一下 xff08 建议大概看文字 xff0c 不理解不要紧 xff0c 然后再看图的执行步骤然后在结合文字 xff0c 这样一切就
  • C语言-----结构体内存对齐

    结构体内存对齐规则 xff1a 第一个成员在结构体变量偏移量为0 的地址处 其他成员变量要对齐到某个数字 xff08 对齐数 xff09 的整数倍的地址处 对齐数 61 编译器默认的一个对齐数与该成员大小中的较小值 vs中默认值是8 Lin

随机推荐

  • dpi计算 density 取值范围

    PPI DPI计算公式 Density 61 sqrt span class token punctuation span span class token punctuation span span class token car wp
  • Repo 流程

    First repo init creates the repo directory clones the git repository https android googlesource com tools repo to repo r
  • *** buffer overflow detected ***: terminatedAborted (core dumped)解决

    在执行一个程序的时候出现了下面的这个错误 xff0c 明明在Ubuntu下面已经编译好了 xff0c 执行的时候除了问题 xff0c 于是换了台电脑尝试还是一样 buffer overflow detected terminated Abo
  • 虚拟机Ubuntu远程启动Jetson nano RVIZ图形界面失败

    INFO 1644470251 178517 Rosapi started map manager 6 process has finished cleanly log file home jetson ros log fb3115c6 8
  • YOLOv5训练自己的数据集实现视频的识别

    写在前面 我本来是使用这个模型进行手写签名的定位 xff0c 但是因为比赛的主办方原因 xff0c 数据不允许公开 xff0c 所以我使用动物世界的一段开头视屏来制作我的数据集 这整个模型跑通的过程中 xff0c 我参考了很多不错的博客 x
  • stm32---OLED(SSD1306)

    OLED模块优缺点 优点 xff1a 尺寸小 xff0c 分辨率高 xff0c 低压3 3V就可工作 xff0c 支持多种接口方式 xff0c 该模块提供了总共4种接口包括 xff1a 6800 8080两种并行接口方式 4线的穿行SPI接
  • stm32---ADC模数转换

    ADC xff1a 模数转换器 xff0c 将模拟信号 xff08 0v xff0c 3v xff0c 6v等 xff09 转换为表示一定比例电压值的数字信号 xff08 1 xff0c 2 xff0c 3等 xff09 STM32F10x
  • stm32---DMA

    DMA 全称Direct Memory Access xff08 直接存储器访问 xff09 xff0c 把一个地址空间的值 复制 到另一个地址空间 xff0c 使用DMA传输方式无需CPU直接控制传输 xff0c 通过硬件为RAM和IO设
  • STM32通信---CAN

    一 CAN是什么 xff1f CAN xff0c 全称为 Controller Area Network xff0c 即控制器局域网 xff0c 是一种多主方式的串行通讯总线 xff0c 是国际上应用最广泛的现场总线之一 二 CAN的起源
  • 计算机网络学习笔记3-抓包工具的使用

    Wireshark win64 2 6 2的使用 安装一路next 在发送数据之前 运行抓包工具 当数据发送之后 记得停止抓包
  • linux运行java项目的shell脚本

    bin bash WORKDIR 61 home xiaohong Baowen cd WORKDIR WEB INF classes for file in 96 ls WORKDIR WEB INF lib jar 96 do CLAS
  • 基于STM32F103的智能门禁系统

    0 前言 本人大二软工菜鸟一枚 xff0c 大神不喜勿喷 1 功能演示 点这里功能演示 2 硬件选型 序号名称备注1STM32F103C8T6开发板用于主控2AS608指纹模块指纹解锁3RFID RC522射频模块刷卡解锁40 96寸四针O
  • uboot的环境变量相关源码分析

    一 uboot的环境变量基础 1 1 环境变量的作用 1 让我们可以不用修改uboot的源代码 xff0c 而是通过修改环境变量就可以影响uboot运行时的一些特性 譬如说修改bootdelay环境变量就可以更改系统开机自动启动时倒计时的秒
  • uboot移植Linux-SD驱动代码解析

    一 uboot与linux驱动 1 1 uboot本身是裸机程序 1 狭义的驱动概念是指 xff1a 操作系统中用来具体操控硬件的代码叫驱动 广义的驱动概念是指 xff1a 凡是操控硬件的代码都叫驱动 2 裸机程序中是直接使用寄存器的物理地
  • 移植三星官方的uboot到x210

    1 移植前的准备工作 1 1 三星移植过的uboot源代码准备 1 三星对于S5PV210的官方开发板为SMDKV210 xff0c 对应移植的 uboot smdkv210 tar bz2 1 2 SourceInsight准备 1 移植
  • 4g模块与51单片机通信

    本文硬件选自忆佰特的4g模块和老陈的上官一号 第一步先使用电脑配置4g模块 xff0c 配置好后再与51单片机进行接线完成通信 xff0c 需要提前插入SIM卡 xff0c 接线如下 通电后模块右下角会亮起红灯 xff0c 并且右上角四颗l
  • 用51单片机IIC协议OLED显示汉字

    接线如下 xff1a IIC协议 xff1a xff08 IIC全称Inter Integrated Circuit 集成电路总线 xff09 由PHILIPS公司在80年代开发的两线式串行总线 xff0c 用于连接微控制器及其外围设备 I
  • Linux中的open()、write()与read()函数,超详细

    open xff08 xff09 函数 xff1a int open const char pathname int flags mode t mode 使用open函数需要的头文件 xff1a include lt sys types h
  • C语言结构体对齐,超详细,超易懂

    结构体对齐规则 结构体的第一个成员总是存放在结构体变量开辟的空间的起始地址其它成员变量要存储在一个名叫对齐数的整数倍的地址结构体总大小为最大对齐数的整数倍 xff0c 结构体内每一个变量都会产生一个对齐数 xff0c 取其最大的对齐数如果是
  • 51单片机之串口通信、WiFi模块、蓝牙模块、4G模块

    目录 串口通信 全双工通信 xff08 打电话 xff09 TTL电平 UART 字节帧 串口相关的寄存器 串口的工作模式 蓝牙模块HC 08 HC 08的AT指令 编辑 WiFi模块ESP8266 配置WiFi模块作为客户端连入当前局域网