欢迎光临散文网 会员登陆 & 注册

51单片机编程开发(九)之UART通信应用

2022-08-01 18:31 作者:落木青云  | 我要投稿

51单片机UART通信接口

通过上一节的学习,我们知道51单片机UART通信要实现通信需要RX和TX两跟线,再加上电源VCC,GND则是4线。如果两通信芯片是共电源,那我们直接交叉连接他们的RX,TX就行了。当然在很多两芯片工作环境电压是相同,但他们没有共电源,这时候我们就使用RX,TX和GND这三根线进行连接。如果遇到两芯片工作电压不一致时我们就需要做电平转换电路,最简单的就是分别在RX,TX上使用MOS管进行隔离,但这需要具体问题具体分析了,有兴趣的朋友可以了解一下。

如果两通信端的电平差别实在是太大,甚至有些可能出现负电平的,这可怎么进行通信呢?我们知道我们使用的51单片机串口引脚输入输出信号电平是TTL电平,它是识别不了负电平的呀!这时就需要制定一些特定的统一通信接口或协议进行对这些通信进行规范了。

串口通信最早的通信规范就是RS-232。串行口标准RS-232是美国电子工业协会(EIA)和国际电报电话咨询委员会(CCITT)为串行通信设备制定的一种标准。该标准规定:RS-232C采用负逻辑规定逻辑电平,-5~-15V为逻辑“1”电平,5~15V为“0”电平。

看完这个标准很多人可能更懵了吧,怎么使用负逻辑规定逻辑电平呢?其实这只是一个规定而已啦,大家也不用太在意,就像A为啥使用符号“A”一样的道理。PC的串行口遵循RS-232标准,但一般情况下,我们使用常用的数字芯片都是TTL或CMOS电平信号(忘记这两种电平定义的朋友赶紧温顾一下数字电路教材)。当单片机和计算机进行通信时就需要一些特定的硬件电路。

计算机串口模块

这个图就是计算机的串口模块,当然现在这样的模块基本上退出历史舞台了,由于串口通信速率慢所以现在计算机上的串口都被USB口代替了。很多人应该都没见过这玩意的吧,我也只是在上大学的时候在实验室老师的杂物堆里翻出来过,当时还挺稀奇的。有人可能会说现在很多显卡或显示屏上还带有这样的接口,那还是比较常见呀。这样说是完全不对的哈,两者只是看起来有点像,但完全没半毛钱的关系呢!那是显示器的VGA接口,插针排数都不一样的吧?当然现在这玩意也快要退出历史舞台了。就问一句你的电脑上那个接口是不是一直闲置的。如果不是那说明的你的电脑历史应该蛮悠久了哟,是不是要换一台为今年的消费做些贡献呢?

USB转串口

买过开发板的初学者应该见过上面这样的线吧,由于计算机早没了串口接口,我们使用单片机与计算机进行通信就可能会使用上图这样的USB转串口线。不过现在这种线用得也越来越少了,更多的被USB线替换了,并且项目开发时用它的概率也不大,它现在主要用在一些已有的旧产品上。现在新出的产品基本都会使USB线来代替它,比如打印机。

CP2102模块

上图就是我们现在开发时下载程序或查看数据时经常使用的一种USB转串口小工具,相比于前面的工具应该是方便很多了吧。

上面的模块都离不开一个东西,那就是串口芯片,当然这是一类芯片,常见的有MAX232,CH340,CP2102等等。这些芯片在价格,性能方面各有特点,其中MAX232是最初的一种,它的电路会相对复杂一点,还需要一些外围电路。像CP2102这样的芯片其应用电路就非常简单,连晶振都不需要了,基本上一个芯片就能实现功能。

RS232


CH340


CP2102

以上图中内容就是这几个芯片的基本应用电路,以后设计电路时如果产品包含与计算机进行串口通信的功能,则可以使用这些芯片,并且在芯片选型时需要综合考虑一下。当然这些芯片都是很普通的,现在国产的也非常有竞争力,国外的芯片这两年由于产能限制价格都高的离谱。所以当你走向工作岗位时可能会发现你们公司很多芯片都在被国产代替,除非一些还没替代料的,不得不用进口芯片。一般普通民用产品基本国产或台产的都能解决,但在计算机,汽车或医疗等高端电子行业现在国产替代率相对比较低,毕竟国产性能还有待提升。当然在国防,军工,高铁,大飞机等涉及到国民安全的领域肯定是能国产就一定国产的。

这几年自贸易战之后国家对半导体制造业也是支持很多,投入很大,不管现在情况怎么样这都是一件好事,一旦这个行业壮大起来这绝对能带动一大批就业,从材料研究,芯片设计,制造,人才培养等方方面面,就像二十年前的互联网行业一样,万物复苏。现在的电动车行业,国产技术已经完全可以秒杀欧洲,日本了,希望未来半导体行业也能实现弯道或换道超车。现在国内芯片制造领域高端人才太稀缺,这类型的人才在市场上永远是供不应求的,所以对于电子专业的学生,如果基础和天赋都不错,又有志于投入半导体行业,那在这个专业继续深造未来绝对前程似锦。现在中国是最大的芯片需求国,并且未来很长一段时间还会是这样,特别是高端芯片制造,国家肯定是想攻克的,但这个过程肯定很艰难耗时也会比较久。过去近二十年时间国内互联网行业发展这么快,但这两年确实是在降温了,技术是不断在更新换代,但动力在减小,除非又有新的革命性的技术爆发。另外部分原因可能是大家都深刻认识到了没有硬件核心技术的互联网产业是没有安全感也没骨气的,就像之前TikTok一样任人摆布。另外所有大厂都去搞短视频,直播或游戏,最后再加个“元宇宙”,到处充满奶头乐,年轻人都活在虚拟世界里,最后大家都指望国家印钱发钱还是让人工智能取代人类?这话虽然说的夸张了一些,但确实是需要思考的一个问题。扯远了,这都是未来的生活了,下面接着写我们的主题。

51单片机与计算机通信

首先我们先来了解一下51单片机与计算机进行通信的实现方法。先来看一个实现这个功能的基本电路。

电路示例

图中的P1就是仿真用的一个串口接口,这个仿真电路要实现与计算机通信功能需要用到其他两个软件,一个是虚拟串口驱动软件,另外一个是串口助手软件,这两个软件在网上都很容易找到。我使用的是Virtual Serial Port Driver和丁丁串口助手,你也可以使用自己熟悉的软件,如果找不到或使用,安装这两个软件有问题可以私信。

虚拟串口驱动软件安装后配置两个成对的虚拟串口一个对应仿真电路中的串口接口,一个对应在串口助手软件上,这样就相当于将两个软件通过虚拟串口连接在一起了,将他们配置成相同的串口参数之后,这时就可以实现相互发送信息了。

这里需要注意的一个问题,上一篇文章中最后部分列举了一个关于使用12MHz和11.0592MHz两种晶振配置特定波特率对应定时器数据寄存器的数据对应的表格,里面还包含各配置值对应的波特率精度,从图中可以看出使用12MHz晶振时误差率普遍比较大,而使用11.0592MHz时几乎没有误差,所以现在知道为啥你手上的单片机使用的晶振都是11.0592MHz的了吧!虽然使用12MHz的晶振进行通信计算机也能捕获到数据,但为了保险起见,若日后你使用51单片机开发项目需要使用到串口时要注意晶振的选择,当然如果使用其他单片机就要另说了,最简单的比如STC生产的1T型的51单片机(即一个机器周期等于一个时钟周期,它的执行效率理论上是传统单片机的12倍,实际因程序复杂程度不一会低一点),就需要参考对应说明了。

虚拟串口驱动


串口助手设置


仿真电路串口设置

接下来我们要怎么验证单片机与计算机进行通信了呢?我们现在就编程实现计算机串口助手发送数据,单片机收到数据就做出回应将数据回传给计算机。

现在我们先来看看程序的具体实现过程。

/*

*这是一个串口通信应用程序

*目的是将串口助手发送过来的数据回传

*/

#include <reg52.h>

#include <intrins.h>


typedef unsigned char u8;

typedef unsigned int  u16;


u8 data_L,data_H;

u8 T0_cnt = 0;

u8 T0_s = 0;

u8 T1_cnt = 0;

u8 crol = 0xfe;

u8 temp = 0;


u8 code num_codelist[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};


void delay(u8 ms);

void data_init(void);

//void Timer_init(void);

void display(void);

void uart_init(void);


void main(void)

{

// Timer_init();

uart_init();


while(1)

{

data_init();

display();

}

}


void delay(u8 ms)

{

    u8 i,j;


    for(i=0; i<ms; i++)

    {

        for(j=0; j<110; j++)

        {

            ;

        }

    }

}


void data_init(void)

{

    data_L = T0_s%10;

    data_H = T0_s/10;

}


void display(void)

{

P2 = 0xfe;

P0 = num_codelist[data_H];

delay(1);


P2 = 0xfd;

P0 = num_codelist[data_L];

delay(1);

}


void uart_init(void)    //串口初始化

{

    TMOD = 0x20;

    SCON = 0x50;

    TH1 = 0xFD; //9600

    TL1 = TH1;

    PCON = 0x00;

    EA = 1;

    ES = 1;

    TR1 = 1;

}


void uart() interrupt 4  //串口中断

{

if(RI)

    {

        RI = 0;

        temp=SBUF;

  SBUF=temp;

  while(TI==0);

  TI=0;

    }

}

现在来看一下程序的仿真效果:

仿真结果

可以看到串口助手发送的数据马上又被单片机传回来了。这个程序没有多少新的代码,主要就是void uart_init(void)和void uart() interrupt 4这两个函数,其中一个串口初始化函数,另一个是串口中断函数。void uart_init(void)这个函数里面设置串口模式,定时器计数值以及串口中断设置。void uart() interrupt 4串口中断函数里面非常简单,就是获取收到的数据然后将数据发送出去。

程序实现过程是非常简单吧,看到这里赶紧去试试看吧。

51单片机双机通信

在项目开发时我们用到串口更多是和其他芯片进行通信,所以这里我们再来实现一个单片机双机通信的例子,先来看看这个电路图。

电路示例

现在来看看我们要实现双机通信的代码:

/*

*这是一个串口通信应用程序

*目的是实现单片机的双机通信

*/

#include <reg52.h>

#include <intrins.h>


typedef unsigned char u8;

typedef unsigned int  u16;


sbit key1 = P3^0;

sbit key2 = P3^1;

sbit key3 = P3^2;

sbit key4 = P3^3;


u8 data_L,data_H;

u8 T0_cnt = 0;

u8 T0_s = 0;

u8 T1_cnt = 0;

u8 crol = 0xfe;

u8 temp = 0;


u8 temp_key = 0; //定义一个变量用来存放临时按键值

u8 key_num = 0;//定义一个数字,用来显示


u8 code num_codelist[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};


void delay(u8 ms);

void data_init(void);

//void Timer_init(void);

void display(void);

void key_init(void);

void uart_init(void);


void main(void)

{

// Timer_init();

key_init();

uart_init();


while(1)

{

data_init();

display();

}

}


void delay(u8 ms)

{

    u8 i,j;


    for(i=0; i<ms; i++)

    {

        for(j=0; j<110; j++)

        {

            ;

        }

    }

}


void data_init(void)

{

    data_L = key_num%10;

    data_H = key_num/10;

}


void display(void)

{

P2 = 0xfe;

P0 = num_codelist[data_H];

delay(1);


P2 = 0xfd;

P0 = num_codelist[data_L];

delay(1);

      P1 = key_num;      //P1端口LED显示

}


void key_init(void)    //按键初始化

{

    IT0=1;                 //外部中断0为下降沿触发

    IT1=1;                 //外部中断1为下降沿触发

    EX0=1;                 //开EX0中断

    EX1=1;                 //开EX1中断

    EA=1;                  //开总中断

}


void uart_init(void)    //串口初始化

{

    TMOD = 0x20;

    SCON = 0x50;

    TH1 = 0xFD; //9600

    TL1 = TH1;

    PCON = 0x00;

    EA = 1;

    ES = 1;

    TR1 = 1;

}


//外部中断0服务例程

void P3_2_key_func(void) interrupt 0            

{

    //将外部中断0对应的按键K3设置为按键加功能

    if(0 == key3)

    {

        delay(15);

        if(0 == key3)

        {

            if(key_num < 100)

            {

                key_num++;

            }

            else

            {

                key_num = 0;

            }

        }

  

  SBUF = key_num;  //串口发送

  while(TI==0);

  TI=0;

    }

}


//外部中断1服务例程

void P3_3_key_func(void) interrupt 2            

{

    //将外部中断0对应的按键K4设置为按键减功能

    if(0 == key4)

    {

        delay(15);

        if(0 == key4)

        {

            if(key_num > 0)

            {

                key_num--;

            }

            else

            {

                key_num = 100;

            }

        }


  SBUF=key_num;  //串口发送

  while(TI==0);

  TI=0;

    }

}


void uart() interrupt 4

{

if(RI)

    {

        RI = 0;

        key_num = SBUF;   //串口接收

    }

}

将这段代码同时下载到两个单片机中就实现两个单片机同步了,现在看看仿真结果:

仿真结果

这个程序中的大多数代码都是前面的文章中类似的,只做简单修改就可以,接下来的时间自己看这代码理一理逻辑,如果有理解不了的地方再留言或私信吧。

结语:

上面已经讲串口的应用做了简单是说明,看完后还需要多动手试试,你手头上的单片机不一定和我这里的电路相同,所以要根据自己的实际情况做更改,有疑问的朋友记得留言或私信。如果觉得有用赶紧分享给朋友吧。若发现错误请指正,感谢支持!

51单片机编程开发(九)之UART通信应用的评论 (共 条)

分享到微博请遵守国家法律