【串口之深得我心】

深入串口@通信

串口通信简介

你好! 如果这是你第一次使用 串口 ,那么了解一些串口是什么以及怎么用吧。

串口是什么

一般来说,单片机与上位机之间以串口通信为主,就串口通信而言。常用的几种通信方式,包括串口自定义协议、Modbus协议、CAN总线。重点介绍一下串口通信。
在这里插入图片描述

IDEA想法

现在小铭有一台电脑和一个外设,现在他想让外设给电脑发送一个字母A。怎么办呢?我们知道计算机的世界只有0和1。那么用0和1怎么发送A甚至是任意数据呢?

假设我们每次发送一个字节那么它要么是0要么是1,接下来我们一次发送8个字节则依然是每一位为0或者1。但是注意到

在这里插入图片描述
也就是说第一位可以代表1个数字,第二位代表2个数字…第八位可以代表128个数字,那么这八个字节可以代表1+2+4+8+16+32+64+128=255个数字。如果对照ASCII表
在这里插入图片描述
基本上可以发送所有字符。

通信

好了,现在我们按照ASCII上对应关系开始发送数据吧。还是以A为例。A对应的十进制是65。 65=1+64。那么我们可以让第一位是1,第7位也是1,其他位为0。

在这里插入图片描述
现在我们已经成功的发送了A。
此外还得规定通信速率也就是波特率每秒发送的位数。这里就不详细介绍了。

单片机实现串口通信

51单片机

要想使用串口就要了解一下两个寄存器和定时器。
(1)串口控制寄存器 SCON
在这里插入图片描述
SCON=0x40 工作方式1;0100 0000 串口不接受数据

SCON=0x50 工作方式1;0101 0000 串口接受数据

(2)电源控制寄存器 PCON

在这里插入图片描述

PCON=0X80;波特率加倍

PCON=0X00;波特率不加倍

(3)TMOD 计数器
在这里插入图片描述
这什么玩意?要不我们换一张图看看吧!

在这里插入图片描述
1)

TMOD|=0X20; //设置计数器工作方式 2
TH1=baud; //计数器初始值设置
TL1=baud

2)

TMOD|=0X01;//选择为定时器 0 模式,工作方式1  
TH0=初值
TL0=初值

硬核知识-串口发送字节

了解完以上内容现在我们就可以写一个串口发送的函数了。我们定义函数为uart_init()
在这个函数里我们做这几件事情:
①确定 T1 的工作方式(TMOD 寄存器);
②确定串口工作方式(SCON 寄存器);
③计算 T1 的初值(设定波特率),装载 TH1、TL1;
④启动 T1(TCON 中的 TR1 位);
⑤如果使用中断,需开启串口中断控制位(IE 寄存器)。
如果你要实现不同的功能那么这个初始化的函数也会不一样。这里我们写几个典型的例子:
实现功能:串口把接收到的数据发送回单片机

void uart_init(void)
{
TMOD|=0X20; //设置计数器工作方式 2
SCON=0X50; //设置为工作方式 1
PCON=0X80; //波特率加倍 4800倍后为9600
TH1=0XFA; //计数器初始值设置
TL1=OXFA;
ES=1; //打开接收中断
EA=1; //打开总中断
TR1=1; //打开计数器
}

void uart() interrupt 4//串口通信中断函数
{
u8 rec_data;
RI = 0; //清除接收中断标志位
rec_data=SBUF; //存储接收到的数据
SBUF=rec_data; //将接收到的数据放入到发送寄存器
while(!TI); //等待发送数据完成
TI=0; //清除发送完成标志位
}

串口功能:发送传感器数据,无需中断

void UART_Init(void)
{
SCON=0x50;			//串口通信工作方式1
TMOD=0x20;		//定时器1的工作方式2
PCON=0X00;      //不加倍
TH1=0xfd,TL1=0xfd;	//9600baud	
TI=1;            //这里一定要注意
TR1=1;

}
//如果你有一个返回ADC的函数adc_value()
float buff;
buff=adc_value();
printf("data is %f",buff);
//你就可以成功的把数据在串口助手中显示了

这里我重点介绍一下printf函数
printf 打印调试把数据显示在串口助手中或者是oled屏幕上。
配合上面那个串口初始化函数,然后在头文件中包含#Include “stdio.h”就可以使用了。

printf("welcome to the digatal world";

但是使用printf唯一的不好就是如果要与上位机通信它发送的数据位数不一样;比如说你的数据是3.23;45.13;100.64;数据位数不一样在于上位机通信时会给软件编程造成很大的麻烦。最好是003.23;045.13;100.64;怎么做到呢?小白我编程能力有限,如果有大佬会请留言谢谢!
下面介绍用寄存器收发数据。

void UART_Init(void)
{
	
	TMOD|=0X20;	//设置计数器工作方式2
	SCON=0X50;	//设置为工作方式1
	PCON=0X00;	//波特率加倍
	TH1=0xfd;	//计数器初始值设置
	TL1=0xfd;
	ES=1;		//打开接收中断
	EA=1;		//打开总中断
	TR1=1;		//打开计数器	
}
 void UART_Sendchar(unsigned char d)		  //发送一个字节的数据,形参d即为待发送数据。
{
	 SBUF=d; //将数据写入到串口缓冲
	while(!TI);
	TI=0;
}
void UART_SendString(unsigned char *String)
{
    while(*String)
    {
        UART_Sendchar(*String);
        String++;
    }
}
 UART_Sendchar(65);	//发送A十进制对应的符号是A
 UART_Sendchar('a');//发送a 注意只能单引号
 UART_Sendchar(0x65);//发送e十六进制65对应的符号是e
 UART_SendString("小七");//发送字符串
/*****在这里你应该理解了吧串口发送就是按照ASCII表的规则来的。无论你发的是十进制还是十六进制最后都会转换成对应的符号

//发送浮点数
float b=3.2;//带转化数据
uchar conver_t[4];//一定要定义成**数组**类型
float b=3.2;
sprintf(conver_t,"%f",b);//通过%.1f /%.2f可以改变小数位数
UART_SendString(conver_t);

串口接收中断的设置;一般用于上位机控制

根据接受的数据做出响应,如灯的翻转,之类的
直接上代码!

//串口控制led亮灭
#include "reg52.h"
#include "stdio.h"
sbit  led=P1^5;
unsigned char rec;

void receive_dat( rec)
{
	if(rec==0x00)
	{
		led=0;
	}
	else if(rec==0x01)
	{
		 led=1;
	}
	else if(rec==0x02)
	{
		led=0;
	}
	else
	{
		led=1;
	}
}
void UART_Sendchar(unsigned char d)		  //发送一个字节的数据,形参d即为待发送数据。
{
	 SBUF=d; //将数据写入到串口缓冲
	while(!TI);
	TI=0;
}
void uart_init(void)
{
TMOD|=0X20; //设置计数器工作方式 2
SCON=0X50; //设置为工作方式 1
PCON=0X00; //波特率加倍 4800倍后为9600
TH1=0XFd; //计数器初始值设置
TL1=0xfd;
TR1=1; //打开计数器;
ES=1;		//打开串口中断
EA=1;		//打开总中断
TR1=1;		//打开计数器
ET1=0;	
}

void  main()
{
   uart_init();
   UART_Sendchar('E');
	while(1)
	{
	}
}

void Uart() interrupt 4
{
 	if(RI==1)
{   RI=0;
	rec=SBUF;
	receive_dat(rec);			  
}
	}

注意,本代码不是万能!如果你的程序很简单那么这些代码基本没问题,但是小白我就曾经遇到了一个问题。我在一个项目中用到了两个中断,定时器、串口中断冲突。结果接收上位机的数据相关代码一直不起作用。我以为是串口接收中断函数有问题。在网上查了一下,可能的原因很多。解决办法嘛主流的是增加中断时间,然后还有一个就是改中断号优先级。我都尝试过对我的程序来说没有用。最后无意中在一个帖子看到降低串口波特率。我把9600改为4800后果然有用。遇到问题,多去查查。14亿中国人,几十亿外国人,他们就做的全都对嘛?也会有类似的问题对吧。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值