认识串口 和 蓝牙模块HC08

本文详细介绍了串口通讯的基本概念,包括串行接口的标准如RS-232、RS-422和RS-485,串口的电平标准如TTL和RS232,以及异步通信的理解。还探讨了串口的接线、编程要素,如SBUF、波特率设置,并提供了单片机通过串口与电脑通讯的代码示例,包括发送字符、字符串以及通过中断接收指令控制LED的案例。最后,文章提到了蓝牙模块HC08在串口通讯中的应用及其注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

串口基本认知

串行接口简称串口,通常指COM接口串行接口是指数据一位一位的顺序传送,其特点就是通信线路简单,只要一对传输线就能实现双向通信(全双工),从而大大降低了成本,特别适合远距离通信,但是传送速度较慢。  

串口关于电器标准和协议

RS-232

也称为标准串口,最常用的一种串行通讯接口,比如我们电脑主机的9针串口,最高速率是20kb/s,RS-232是为点对点设计的,最长传输距离为15m,适合本地设备之间的通信。

RS-422

支持点对点的双向通信,最大传输距离为1219米,最大传输速率为10Mb/s。

RS-482

是从RS-422基础上发展而来的,无论四线还是二线连接方式总线上可多接32个设备。

串口的电平

这里要提到经常听说的UART,UART是指异步串行,通过异步接收/发送,UART包括TTL电平的串口和RS-232电平的串口,所以串口的概念比UART大一点。

怎么理解异步通信?

由于单片机和电脑,不同设备的频率和配置不同,因此CPU运行速度不同,所以各自使用各自的时钟来相互配合。

RS232电平和TTL电平有什么区别?

对于RS232逻辑1是 -3 ~ -15V的电压,逻辑0是 3 ~ 15V 的电压

TTL电平是晶体管-晶体管逻辑的简称,TTL电平信号应用广泛,是因为其数据表示采用二进制规定,+5v等价于逻辑1,0v等价于逻辑0。 在数字电路中,由TTL电子元器件组成电路的电平是个电压范围,规定:

输出高电平>=2.4V,输出低电平<=0.4V; 

输入高电平>=2.0V,输入低电平<=0.8V;

串口的接线

笔记本电脑通过TTL电平和单片机通讯:TX发送线(端口);RX接受线(端口),并使用CH340进行USB转TTL。

RXD:数据输入引脚,数据接收;STC89系列对应P3.0口,上官一号(即我使用的STC开发板)有单独引出

TXD:数据发送引脚,数据发送;STC89系列对应P3.1口,上官一号有单独引出

注意,如果需要自己接线的化,应该交叉接线,TXD接RXD, RXD接TXD!

串口的编程要素

输入和输出的数据缓存器叫做SBUF,都用99H的地址代码,但是是两个独立的8位寄存器。

代码体现为:想要接收数据 char data = SBUF  (将缓存器的值读取到data)        

                      想要发送数据 SBUF = data;  (将data的值写入缓存器)

再次回忆UART的概念,”由于单片机和电脑,不同设备的频率和配置不同,因此CPU运行速度不同,所以各自使用各自的时钟来相互配合。”  所以双方需要约定通讯速度,这个速度就叫做波特率,对于电脑来说,别人做好了软件,鼠标点点就能配置好,而单片机的波特率则需要自己写代码。

对于电脑来说,需要点击配置的东西是:

 所以在代码中,我们也需要配置波特率校验位停止位。那在代码中的这些如何进行设置?答案还是,和设置定时器模式一样,要操控寄存器而且,也和定时器一样,代码也可以从stc-isp助手里面得到: 注意!这里的波特率设置应该和之前电脑设置的波特率(最左侧的红圈)相同。

PCON寄存器为电源控制寄存器,最高位BIT7为 SMODSMOD = 0 时,波特率不加倍; SMOD = 1 时,波特率加倍,此处设置波特率不加倍。

SCON寄存器为串行控制寄存器,BIT7和BIT6分别是SM0SM1,其值的组合会对应不同的功能:

 此处设置8位可变波特率。

SM2为多机通讯相关位;REN为串口数据接收的允许位

代码实现单片机向电脑发送一个字符

#include "reg52.h"
#include "intrins.h" //这个库加了,delay函数里面的nop()才不会报错

sfr AUXR = 0x8E; //配置了这句话,才可以在UART的初始化里写AUXR寄存器,原因见STC89系列的手册

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
}


void main()
{
	char msg = 'a';
	UartInit();
	
	while(1){
		SBUF = msg; //往发送缓冲器里写入数据,就完成了数据的发送
		Delay1000ms();
	}
}

实现效果1

代码实现单片机向电脑发送字符串

在刚刚提到的SCON寄存器中,BIT1为TI:

即,每发送一个BYTE(一个char变量的大小),TI就会被硬件置1,根据这个,我们可以编写使串口打印字符串:

#include "reg52.h"
#include "intrins.h" //这个库加了,delay函数里面的nop()才不会报错

sfr AUXR = 0x8E; //配置了这句话,才可以在UART的初始化里写AUXR寄存器,原因见STC89系列的手册

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
}

void printSTR(char *msg)
{
	while(*msg != '\0'){
		SBUF = *msg; //往发送缓冲器里写入数据,就完成了数据的发送
		while(TI == 0); //只有当TI为1时,才往下走,根据手册,TI只有在发送完8位数据后才会硬件自动置1
		TI =0;
		msg++;
	}
	
}
void main()
{
	//char *msg = "mjm";
	UartInit();
	
	while(1){
		printSTR("mjm\r\n"); //在串口中。"\r\n"才是换行
		Delay1000ms();
	}
}
	

实现效果2

代码实现使用串口点亮单片机LED

在刚刚提到的SCON寄存器中,BIT0为RI:

即收到数据后,RI位会由硬件置1。

同时,使用中断的方式接收指令可以使得响应没有延时

为了打开中断,还需查看手册:

 所以,打开UART中断需要打开ES和EA

#include "reg52.h"
#include "intrins.h" //这个库加了,delay函数里面的nop()才不会报错

sfr AUXR = 0x8E; //配置了这句话,才可以在UART的初始化里写AUXR寄存器,原因见STC89系列的手册
sbit D5 = P3^7;

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
}

void printSTR(char *msg)
{
	while(*msg != '\0'){
		SBUF = *msg; //往发送缓冲器里写入数据,就完成了数据的发送
		while(TI == 0); //只有当TI为1时,才往下走,根据手册,TI只有在发送完8位数据后才会硬件自动置1
		TI = 0;
		msg++;
	}
	
}
void main()
{
	//char cmd;
	//char *msg = "mjm";
	UartInit();
	D5 = 1;
	
	ES = 1;
	EA = 1; //打开中断!
	
	while(1){
		printSTR("mjm\r\n"); //在串口中。"\r\n"才是换行
		Delay1000ms();
/*		if(RI == 1){ //RI = 1时数据接收完毕
			cmd = SBUF; //从SBUF里面读发来的数据
			
			if(cmd == 'o'){
				D5 = 0;//开灯
			}else if(cmd == 'c'){
				D5 = 1;//关灯
			}
			
			RI = 0;//软件复位
		} */
	}
}

void UARTinter() interrupt 4 //由于不管TI还是RI置1时,中断都会发生,所以为了逻辑严谨,可以在中断处理函数中添加判断
{
	if(RI == 1){ //如果是RI引起的中断
		char cmd;
		cmd = SBUF; //从SBUF里面读发来的数据
			
		if(cmd == 'o'){
			D5 = 0;//开灯
		}else if(cmd == 'c'){
			D5 = 1;//关灯
		}
			
		RI = 0;//软件复位
	}
	
}	

实现效果3

这次试验就很好的体现了串口的"全双工“,即可以不断同时的发送和接收数据。

同时注意,在”发送缓冲区”中选择文本模式后要注意,在文本模式下输入的任何东西都会被认为字符,如果输入1,则为字符1,对应ASCII码中是数字49!!!

实现效果3的拓展

以上的代码实现的是接收字符来点亮LED,如果是想要使用字符串来控制点亮LED,需要修改代码:

//新定义的全局变量//
char flag;
char cmd[12];
char open[12] = "open\r\n";//由于要使用strcmp,所以将长度设置相同
char close[12] = "close\r\n";

//新定义的函数//
void Dealstr()
{
	if(flag == 1){
		if(strcmp(cmd,open) == 0){ //相等返回0
			D5 = 0;//开灯
		}else if(strcmp(cmd,close) == 0){
			D5 = 1;//关灯
		}
		flag = 0; //将flag清0
		memset(cmd,'\0',12); //将字符串清空
	}
}

//新的中断处理程序//
void UARTinter() interrupt 4 
{
	if(RI == 1){ //如果是RI引起的中断
		static int i = 0; //此时这句命令只会被执行一次。避免每次发生中断i都会清0
		
		if(SBUF != '\n'){
			cmd[i] = SBUF; //从SBUF里面读发来的数据
			i++;
		}else{
			cmd[i] = '\n';//将刚刚判断而导致没有写上去的\n加上
			cmd[i+1] = '\0';//加上字符串结束符
			i = 0;
			flag = 1;
		}
		
	Dealstr();
	RI = 0;//软件复位
	
}
	
}

如此一来,在串口中输入"open“加上换行键再按下发送数据就可以点灯;同样输入”close"加上换行键再按下发送数据就可以关灯。

使用蓝牙模块HC08进行串口通讯

注意!蓝牙的RXD要和串口的TXD相连,同理,蓝牙的TXD要和串口的RXD相连。使用上左图的蓝牙模块(内置波特率9600,正好可以对应)再使用右图扫码小程序,搜索“HC08"即可连接成功!

同时!虽然在WINDOWS中的串口中,换行符是“\r\n",但是在ios系统中的串口中,换行符依然是”\r"!所以代码需要略微修改,将open和close字符串的定义中的"\r"给去掉!

//char open[12] = "open\r\n";//windows
//char close[12] = "close\r\n";//windows
char open[12] = "open\n";//ios
char close[12] = "close\n";//ios

最终的界面是这样:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值