这次我们来学习
串口通信。串口跟USB一样也是一种接口,只不过它不叫USB而是叫COM口。一般的单片机里面都集成了串口这玩意儿,有了串口,我们的单片机就可以跟其他拥有串口的设备进行通信了,我们的电脑也有串口,稍微老些的的主板直接在主板后面提供了串口接口,而目前的主板一般只在主板上做成排针,用到的时候需要引出来才可以用(电脑的串口需要做电平转换才能和单片机进行通信哦!如果是用USB转串口 的方式就不需要啦)。
串口就相当于我们平时使用的快递,把这边的数据传送到别的地方去,当然啦,用串口不花钱,用快递是要花钱滴~~
比如说电脑上有串口,因此我们可以把单片机采集到的信息(比如温度,压力或者其他数据)快递给电脑,在电脑上显示或者是运用这些信息进行处理。比如我们要做一个电池测量仪,我们把单片机采集到的电池电压和电流信息申通快递到电脑端,由电脑端进行显示并记录,最后算出电池的容量以及电池的放电曲线等等,同样,我们也可以运用一些传感器,测量我们的体温,脉搏等信息并反馈给电脑,由电脑进行计算,分析你的身体状况,是不是很酷呀?
既然能把信息通过串口传给别人,那么自己肯定也能接收到别人传给自己的信息啦!假设我在电脑上做了个小软件,点一下这个按钮就会通过串口给单片机发送一段命令,单片机收到后执行它,比如说我点一下按钮,电脑就会通过串口给单片机发送一个开灯的命令,单片机收到开灯命令后就控制继电器的闭合来达到把电灯打开的效果,点击另一个按钮,就会启动电视机,洗衣机,甚至是工厂的设备,如果结合网络,我甚至可以在千里之外控制这些设备,是不是更酷啦?
好了,废话了一堆,下面讲讲该怎么使用串口与别的设备进行通讯。在单片机中,串口是标有
TXD 和
RXD 的引脚,像 STC11F02E 单片机的就是第二(P3^0)和第三引脚(P3^1),TXD 是用来发送信息的,就像你发快递时,快递单上填写的发送人一栏,RXD 是用来接收信息的,就相当于收件人啦!因此发送设备的发送端口 TXD 要接到接收设备的接收端口 RXD,假如你发现无法通信,查了半天程序发现没错啊,没准是线没接对哦!除了这两根线,公共地 GND 也要接上才行撒~~也就是说,完成串口通信需要接3根线,
TXD、RXD、GND。
在单片机中,串口是通过一个寄存器来控制的,我们可以把这个寄存器看做是8个叫做
SM0 、SM1 、SM2、 REN 、TC8、 RB8 、TI、RI 的开关。
其中
SM0 和
SM1 的配合用来控制串口的工作方式的
我们平时比较常用的是 方式1 即
SM0=0,SM1=1的时候,其他方式小七就不解释了,大家感兴趣可以百度一下。
有时候呢,会有一种情况,外部有信息通过串口传过来(也就是快递到啦),可是我们并不想接收它,怎么办呢?这里有一个开关来是用来控制串口是否允许接收数据的,这个开关就是
REN ,当REN=0时,禁止串口接收外部传来的信息(拒签快递),当REN=1时,允许接收。
串口里面有个
串口发送中断请求标志 TI ,它就相当于显示快递的状态,我们用串口把数据传出去,如果数据已经传完了(收件人已经签收),那么这个 TI 标志的值就会变成1,并产生一个中断告诉你数据已经发送完了(发短信通知你对方已经签收),这时你必须把 TI 清零才行,不然它会一直产生中断,烦死你.....同理,
RI 是串口接收中断请求标志,当数据接收完时也会变成 1 ,也需要你对它进行清零。当然了,上面所说的中断必须要有
ES(串行口中断允许)这个总开关同意才行,也就是说,当快递送到了,TI会变成1,但要不要短信通知你,就需要ES 这个开关来设定。ES =1 时允许串口收到或者发送完数据后产生中断(短信通知),ES=0 时发送或接收到数据后不会产生中断(不通知)。
一旦数据发送(接收)完成,TI(RI)总会变为1的,所以要想知道快递有没有送到,除了让送快递的通知,我们也可以上网查呀!当我们查到TI=1时,就说明数据已经发出去了,当查到RI=1时,就说明数据已经接收完毕。
就像快递一样,有的很快,也有的很慢。我们把串口通信的速率叫做
波特率,即一秒钟能传多少数据,波特率越高,数据传得也就越快,当然也不是越高越好啦,就像我跟你讲话一样,我用一般语速跟你讲,你听得很明白,要是我用非常高的语速跟你讲,你就听不清了,所以我们要约定通信的速率,当发送端和接收端的速率都一样时,两者才可以正常的通信。
通常我们用 9600 的波特率进行通信,高点低点都无所谓啦。这个
波特率是用工作在方式2的定时器(自动重装初始值)来产生的,在这里小七提供一个小工具来便捷的计算,如果你想知道是怎么算的,可以百度撒~~波特率的大小跟晶振的大小有关,而12MHZ的晶振不太好计算,所以我们经常使用的是
11.0592MHZ 的晶振,当我们用9600波特率时,算出来的定时器初始值就是 0xFD。
波特率 定时器初始值
19200 0xFD
9600 0xFD
4800 0xFA
2400 0xF4
1200 0xE8
串口通信里面有一个叫做
SBUF 的仓库(寄存器),它存放着你将要发送出去或者接收到的快递(数据),当我们这样写
SBUF = seven 时,就是把 seven 这个变量的数据放到 SBUF 里并通过串口传出去,而
seven = SBUF 呢,就是串口收到内容后,把它存到了SBUF里面,我们把SBUF里面的内容赋值给 seven 这个变量就可以读出数据了。
好了,该说的都说了,下面开始写程序了。由前面知道,在使用串口通信之前,应该对串口进行设置,比如设定串口的工作方式,通信速率等等,工作方式前面说了,我们经常使用的是工作方式1,即
SM0=0,SM1=1 工作方式确定好后设定通信的速率,而通信的速率是通过设定定时器来完成的,
TMOD = 0x20 //设定定时器的工作方式(方式2) 即可设定定时器工作在自动重装初始值的状态(忘了?返回去看看上一个帖子的定时器部分),假若我们设定速率为 9600 bps ,那么定时器的初始值就是 0xfd ,然后启动定时器,这样串口就以9600的通信速率开始工作了,即
TH1 = 0xfd //给定时器装初始值 TL1 = 0xfd TR1 = 1 //启动定时器 串口是开始工作了,但是我们需要当它接收或者发送完数据时产生一个中断告诉我们,不然我们不知道有没有数据发送过来,所以我们还要把ES 这个串行口中断允许开关,和总断总开关 EA打开才行,即
ES = 1 EA = 1
这样,当串口收到消息时它就会产生中断通知我们,就像我们的快递到了,快递员会给你打电话一样。下面开始写一个例子,当收到从电脑端发送过来的小写字母 a 时,点亮蓝色的LED,并通过串口把大写字母 A 发送回去,如果不是小写 a 则点亮红色的LED,并把大写 B 发回去。
完整的程序如下:
- #include <reg52.h>
- sbit led1 = P1^7; //定义白色LED 引脚
- sbit led2 = P1^6; //定义红色LED 引脚
-
- void com_ser() interrupt 4 //串口中断处理函数,收到数据后产生中断,在这里处理
- {
- unsigned char temp; //定义一个变量,用来存放电脑端发来的数据
-
- if(RI) //如果数据已经接收完,即RI=1
- {
- RI=0; //对RI进行清零
- temp = SBUF; //把收到的数据赋值给变量(注意接收的写法)
- }
- if(temp=='a') //判断收到的数据是不是小写的 a
- {
- SBUF = 'A'; //是,则把大写的 A 发送给电脑端(注意发送的写法)
- led1 = 0; //并点亮白色LED
- }
-
- else //如果不是字母 a
- {
- SBUF = 'B'; //把 B 发给电脑端,也可以 SBUF = temp 把temp的值发回去
- led2 = 0; //并点亮红色LED
- }
- while (!TI); //判断数据是否发送完毕,即TI=1,没发完就在这等待
- TI = 0; //发送完后对TI进行清零
- }
-
- void main() //主函数
- {
- /******************设定定时器*********************/
- TMOD = 0x20; //设定定时器的工作方式(方式2)
- TH1 = 0xfd; //设定波特率为 9600 bps (在11.0592MHZ晶振时)
- TL1 = 0xfd;
-
- /*******************设定串口**********************/
- SM0 = 0; //SM0 和 SM1 设定串口的工作方式(方式1)
- SM1 = 1;
- REN = 1; //允许串口接收外部传来的数据
-
- /******************设定中断**********************/
- ES = 1; //允许串口收到数据后产生中断通知我们
- EA = 1; //因为总中断开关是控制所有中断的,所以要把它打开
- TR1 = 1; //启动定时器,串口就开始工作喽!
-
- while (1); //什么都不做,在这等串口的中断产生
- }
程序写好后编译,我们依旧用 STC 11F02E 这个单片机,当然了,你使用别的单片机也行。由于我们的串口需要接上
11.0592MHZ 的晶振,所以我们要在单片机的
XTAL 引脚接上这个晶振,并根据程序的定义,在相应的引脚上接上 LED 。
电路完成后,接上USB转串口数据线 ,打开下载软件,勾选
下次冷启动后使用外部晶振。
下载完成后在右边找到
串口助手 ,并按框框的设置好电脑串口的波特率,发送一个小写的 a 试试,可以发现白色LED 被点亮了,并且在接收区接收到了一个大写字母 A
如果我们发送的不是 a ,比如说 7 ,那么红色的LED就会被点亮,同时电脑端会收到一个大写字母 B
这样我们就可以通过电脑的串口与单片机通信啦,是不是很好玩啊?假如我们把发光二极管替换成继电器,那么我们就可以用继电器控制电灯,电视机,电冰箱……
什么?!!你竟然说这还不算好玩?那我们就来玩些让别人听上去好像感觉很厉害的样子,但是实现起来却很简单的技术:
蓝牙控制技术!
这是淘宝花了25块多买的蓝牙模块,输出的可是串口哦!程序依旧不变,
变的只是把数据线的TXD RXD GND 替换为蓝牙模块的 TXD RXD GND 而已,
注意蓝牙模块的工作电压是3.3V~~不能接5V给它哦,所以你要做个3.3V稳压电路,一般的USB转串口数据线都会有3.3V输出的,接上去就好了,如果没有就用3.3V稳压管做一个吧。
小七用的是安卓手机,有一个软件叫做 蓝牙串口调试软件 ,大家可以在网上找得到的。
打开蓝牙模块的电源,打开蓝牙串口调试软件,搜索到你的蓝牙模块后并连接
连接好后我们就可以通过手机的蓝牙给蓝牙模块发送信息了,而蓝牙模块收到信息后,又会把信息通过串口传给单片机处理。
发送 a
白灯亮了,并返回了大写字母 A
发送7 ,红灯亮了,并返回大写字母 B
这下你们该满意了吧?平时听到的某某公司研究出来了 蓝牙控制电灯 技术,蓝牙控制电冰箱技术,蓝牙XXXX技术,现在是不是觉得很简单啊?那就赶紧发挥你丰富的想象力,运用你所学到的知识,做些好玩有趣的东西并到 创意DIY 板块与大家分享吧!
小七做的蓝牙控制小车 :
如果你会用JAVA编写安卓软件,完全可以写出一个安卓的控制端哦
对了,补充一下,串口一次只能发送一个字符或数据哦,如果我要发送一段字符串呢?那就要用到数组配合循环语句来完成了。
- unsigned char i;
- unsigned char yujv[]=”www.mydigit.cn”;
-
- for(i=0,i<14;i++)
- {
- SBUF = yujv[i]; //一共要发送14个字符,所以要发送14次(循环14次,循环第i次时,把数组里面第i个数据通过串口发送出去)
- while(!TI) //等待第i个数据发送完成
- TI=0; //对TI清零
- }
什么是数组?上一个帖子好像我已经说过了撒, 数组就是把一堆数据从
0开始依次给每个数据编上号比如上面的 unsigned char yujv[]=”
www.mydigit.cn” 就是声明一个叫做 unsigned char 数据类型,且数组的名字叫做
yujv ,里面一共存有14个字符数据 ”
www.mydigit.cn” ,里面的第一个字母w标号为 0 ,当我们要提取这个w时,
yujv[0] 就代表里面的w,同理,第五个字母 m 就是yujv[4],第十四个字母 n 就是yujv[n],上面的是存放字符串的写法,如果要存放不同的数据,就是
yujv[]={12,34,56,78,90} ,一样的,yujv[0]就是数据 12 yujv[1]就是数据34。