【51单片机】(手把手教你)串口通信-基础篇

通信方式

并行

适合短距离通信,并行通信控制简单、相对传输速度快(8位一起传输)。

串行

只能一位一位的传送。

同步(了解)

建立发送方时钟对接收方时钟的直接控制,使双方达到完全同步。此时,传输数据的位之间的距离均为“位间隔”的整数倍,同时传送的字符间不留间隙。
发送方对接收方的同步可以通过外同步和自同步

异步(常)

以字符(构成的帧)为单位进行传输。数据位从低到高传送。
格式:

这里的空闲时间是任意的。

串行通信的制式(传输方向)

单工(仅能沿一个方向)

半双工(可进行双向,但需分时)

全双工

串行通信的错误校验

奇偶校验

在发送数据时,数据位尾随的1位为奇偶校验位(1/0)。奇校验时,数据中1的个数与检验位1的个数之和应为奇数;偶校验时,数据中1的个数与校验位1的个数之和应为偶数。接收字符时,对1的个数进行校验,若字符不一致,则说明传输数据过程中出现错误。

代码和校验

发送方将所发数据块求和(或各字节异或),产生一个字节的校验字符(校验和)附加到数据块末尾。接收方接收数据时,同时对数据块(除校验字节外)求和(或各字节异或),将所得的结果与发送方的“校验和”进行比较,一致则无差。

循环冗余校验

通过某种数学预算实现有效信息与校验位之间的循环校验,常用语对磁盘信息的传输、存储区的完整性校验。

串口的基本结构
串口的基本结构

SBUF:51单片机中的特殊寄存器,串行数据缓冲器(一个接收一个发送),两个其实是共用的一个地址99H,但是两个在物理上面是分开的。
当发送使用时,就采用SBUF=XXX; (XXX为需要传送的数据)
当接收使用时,采用XXX=SBUF;
记得因为是串行的所以传输都是一位一位进行的。
T1溢出率:T1计时器的溢出频率(就是计时器每次低位计满向高位进位时间的倒数)
用处:用于计算波特率(每秒传输二进制代码的位数)

实现单片机与电脑之间的互相传送字符串通信

工具:STC-ISP

代码:

[cpp] view plain copy
#include <reg52.h>  
#include <stdio.h>              //printf头文件  
#define uc unsigned char   
#define uint unsigned int  

uc flag,i,flag_t,s[50]="",j=0,flag_n=0;  
uc code table[]="I get ";          

void init()  
{  
    TMOD=0x20;    //定时器工作方式,选择了定时器1,工作方式2 八位初值自动重装的8位定时器。          
    TH1=0xfd;     //定时器1初值  ,设置波特率为9600 晶振11.0529MHZ?  
    TL1=0xfd;  
    TR1=1;        //开启定时器1  

    SM0=0;  
    SM1=1;        //10位异步接收,(8位数据)波特率可变  
    REN=1;        //允许串行口接收位  
    EA=1;         //允许中断(总闸)  
    ES=1;         //允许串口中断  
}  
void main()  
{  
    init();  
    while(1)  
{  
      if(flag==1)  
    {     if(flag_n!=0)        //使第二个及以后I get xx 换行,不与You transfer在一行(单纯为了格式好看)  
            {TI=1;  
            printf("\n");  
            while(!TI);  
            TI=0;  
            }  
        for(i=0;i<6;i++)  
        {  
            SBUF=table[i];  
            while(!TI);  
            TI=0;  
        }  
            for(i=0;s[i]!='#'&&i<50;i++)  
        {  
            SBUF=s[i];  
            while(!TI);  
            TI=0;  
        }  
        flag=0;  
    }  
    if(flag_t==1)                          //发送完毕之后,在电脑端输出。  
    {  
        TI=1;                              //printf之前必须将T1置为1才行。  
        printf ("\nYou transfer %s",s);  
        while(!TI);  
        TI=0;  
        flag_t=0;  
    }     
}  
}  

void ser() interrupt 4  
{  
        if(RI)       //接收数据,手动将RI清0  
    {         
        RI=0;  

        if(flag==0&&j!=0)//1.循环赋值为'\0'(字符串结尾标志符),j=0,为了第二次传递字符串是又是从头输出  
        {            //2.flag为0和j不为0时,保证是第二次及以后,传输字符串(控制输出格式)  
            flag_n++;              
            for(j=0;s[j]!='#'&&j<50;j++)  
                  s[j]='\0';  
                  j=0;  
        }  
        s[j]=SBUF;  
        flag=1;  
        if(s[j]=='#'||j==49)     //以'#'作为传送字符串的结尾符,我定义的字符数组最长为50所以49也应该结束。  
            flag_t=1;  
        else  
            j++;  
    }  

    if(TI)     //发送数据  
    {  
    }      
}  

运行截图:
运行截图

代码解读:基本上就是几个模块:计时器、中断以及串口通信

中断

寄存器介绍

IE(interrupt enable):(可位寻址)设定各个中断源的打开和关闭
IE Register
IE explain
IP(interrupt prior)中断优先级寄存器:(可位寻址)用来设定各个中断源属于两级中断中的哪一级
dIP Register

中断源:
Interrupt Source

中断响应条件:

1.中断源有中断请求
2.此中断源的中断允许位为1
3.CPU开中断(EA=1)
代码书写:

1.先开总中断EA
2 .然后再开特定的中断去控制
3.如果有特殊需要优先级问题再设置IP
4.中断函数书写 格式
void 函数名() interrupt 中断号(上面图示的序号)
//中断函数返回值一定是void
//函数名随便写
//中断号用来判断是哪个中断源

计时器

寄存器介绍

TCON 支持位寻址 :控制寄存器,控制T1、T0的启动和停止及设置溢出标志
TCON
这里写图片描述

TMOD,不支持位寻址:定时/计数器的工作方式寄存器,确定工作方式和功能
这里写图片描述
这里写图片描述

计时器代码书写步骤:

1.EA=1;

2.ETX=1; //开启计时器X中断

3.配置工作方式 TMOD=0x..; //根据自己需求按照上表来配
3.配置计时器初值

//THX=(65535-N)/256;
//TLX=(65535-N)%256;
//N由你要计时的时长决定。计时器计一个数花费一个时钟周期来计算。

4.TRX=1; //开启计时器X

串口通信

寄存器介绍

PCON电源管理寄存器 :(不可位寻址) 用来管理单片机的电源部分,包括上电复位检测、掉电模式 、空闲模式等
这里写图片描述
这里写图片描述

SCON:(可位寻址)用以设定串行口的工作方式、接收/发送控制以及设置状态标志
这里写图片描述
这里写图片描述

波特率计算
这里写图片描述

SMOD就是PCON中的第一位,默认为0
fosc为晶振频率,所以自己设定不同波特率时,也要考虑晶振不同的问题。

代码书写

1.上面都书写完毕之后
2.还需要ES=1
3.传输数据时,SBUF=XX
接收数据时,XX=SBUF
4.中断函数书写
一定要将RI清0,但是TI的清0在主函数中进行
//因为TI在中断中进行,(1)没有if(TI)的判断,那么就会和RI的处理混淆(2)如果有TI判断
//那么有可能永远进行不了传输数据,因为最开始TI是为0的,无法进入TI条件,就无传
//输数据(SBUF=XX)。而且在传输数据的时候会又一次进入中断,就是还没处理中
//断就又进入了另外一个中断,导致通信出现异常。

相信有了这些模块的讲解之后加上代码的注释应该都懂了~
如果有任何问题和不懂的都可以提出~

以上文章转载自 wait_for_that_day5 的 【51单片机】(手把手教你)串口通信-基础篇。
原文网址:http://blog.csdn.net/wait_for_taht_day5/article/details/50564331

本目录下提供的是《手把手你学51单片机(C语言版)》材中所有例程与作业习题的源代码。 请将整个目录复制到电脑硬盘上使用,如直接在光盘路径下打开工程可能会导致软件报错。 运行目录下的Clean.bat可以清理程序编译过程中产生的中间文件和临时文件。 lesson2 (第2章): 点亮一个LED示例,所在章节2.4 lesson3 (第3章): LED闪烁示例,所在章节3.5 lesson4 (第4章): 4_1:用P0口控制LED的示例,所在章节4.8 4_2:用P0口控制实现流水灯效果,所在章节4.8 4_t4:作业题4,逐次右移的流水灯效果,所在章节4.9 4_t5:作业题5,左右往复移动的流水灯效果,所在章节4.9 lesson5 (第5章): 5_1:基于定时器查询模式的LED闪烁,所在章节5.2.3 5_2:静态点亮数码管的某几段,所在章节5.3.2 5_3:数码管静态显示一位字符,所在章节5.3.3 5_t3:作业题3,定时器查询模式实现左右移动的流水灯,所在章节5.4 5_t5:作业题5,变更lesson5_3的正计数为倒计数,所在章节5.4 lesson6 (第6章): 6_1:数码管动态显示原理示例(if...else if...语句示例),所在章节6.4 6_2:数码管动态显示原理示例(switch...case...语句示例),所在章节6.4 6_3:基于中断带消隐的数码管动态显示示例,所在章节6.5 6_t4:作业题4,在lesson6_3多位数字显示的基础上不显示高位的0,所在章节6.6 6_t5:作业题5,变更lesson6_3的正计数为倒计数,所在章节6.6 lesson7 (第7章): 7_1:基于数码管计时程序的静态变量演示,所在章节7.2 7_2:点亮LED点阵上的一个点,所在章节7.3 7_3:点亮LED点阵上的一行,所在章节7.3 7_4:点亮LED点阵上的全部点,所在章节7.3 7_5:LED点阵显示静态图形,所在章节7.4 7_6:LED点阵显示纵向移动的动画,所在章节7.5.1 7_6_h:LED点阵显示横向移动的动画(掉转板子方向的取巧方式),所在章节7.5.2 7_7:LED点阵显示横向移动的动画,所在章节7.5.2 7_t3:作业题3,lesson7_6的向上移动改为向下移动,所在章节7.6 7_t4:作业题4,lesson7_7的向左移动改为向右移动,所在章节7.6 7_t5:作业题5,基于LED点阵的9~0倒计数,所在章节7.6 7_t6:作业题6,独立LED、数码管、点阵LED同时全亮,所在章节7.6 lesson8 (第8章): 8_1:基于数码管计时程序的函数调用演示,所在章节8.2 8_2:按键基本原理演示例程,所在章节8.4.3 8_3:独立按键扫描原理演示例程,所在章节8.4.3 8_4:独立按键消抖原理演示例程,所在章节8.4.4 8_5:独立按键扫描并消抖的演示例程,所在章节8.4.4 8_6:矩阵按键扫描并消抖的演示例程,所在章节8.4.5 8_7:基于矩阵按键和数码管实现的简易加法计算器,所在章节8.5 8_t4:作业题4,变更lesson8_5的递增计数为递减计数,所在章节8.6 8_t5:作业题5,在lesson8_7基础实现简易加减计算器,所在章节8.6 lesson9 (第9章): 9_1:步进电机驱动的基础示例,所在章节9.3.3 9_2:步进电机转动任意角度的示例,所在章节9.3.4 9_3:实用的步进电机驱动示例,所在章节9.3.5 9_4:按键控制步进电机转动的示例,所在章节9.3.6 9_5:蜂鸣器驱动的基础示例,所在章节9.4 9_6:蜂鸣器演奏简单乐谱——“两只老虎”,所在章节9.4 lesson10 (第10章): 10_1:基于数码管显示的数字秒表,所在章节10.1 10_2:基于PWM方式控制LED的亮度,所在章节10.2 10_3:基于PWM方式控制LED实现呼吸灯效果,所在章节10.2 10_4:交通信号灯示例,所在章节10.3 10_5:长短按键/连续按键功能实现示例,所在章节10.5 10_t3:作业题3,数码管计时与流水灯同时运行的示例,所在章节10.6 lesson11 (第11章): 11_1:普通IO口模拟实现串口通信的示例,所在章节11.4 11_2:单片机硬件UART查询方式实现串口通信的示例,所在章节11.5.3 11_3:单片机硬件UART中断方式实现串口通信的示例,所在章节11.5.3 11_4:UART串口通信及控制数码管显示的示例,所在章节11.6 11_t5:作业题5,UART串口控制流水灯流动和停止,所在章节11.7 11_t6:作业题6,UART串口控制蜂鸣器的开关,所在章节11.7 lesson12 (第12章): 12_1:指针作为函数参数的示例,所在章节12.1 12_2:指向变量的指针与变量关系的示例,所在章节12.2 12_3:指针、字符串、字符数组、ASCII码演示示例,所在章节12.3 12_4:1602液晶基本操作演示示例,所在章节12.4 lesson13 (第13章): 13_1:1602液晶显示两行字符串,并实现整屏的重复左移,所在章节13.2 13_2:多c文件示例,1602液晶显示两行字符串,并实现整屏的重复左移,所在章节13.3 13_3:整型数为操作数的简易+-*/计算器,所在章节13.4 13_4:基于帧模式的实用串口程序示例,所在章节13.5 13_t2:作业题2,1602液晶显示两行字符串,并实现整屏的重复右移,所在章节13.6 lesson14 (第14章): 14_1:寻址I2C总线上存在的和不存在的地址,将应答状态显示到液晶上,所在章节14.2 14_2:用单字节读写模式访问EEPROM,每次+1后写回,所在章节14.3.1 14_3:用多字节读写模式访问EEPROM,依次+1,+2,+3...后写回,所在章节14.3.2 14_4:用连续读与分页写模式访问EEPROM,依次+1,+2,+3...后写回,所在章节14.3.3 14_5:读取EEPROM中的数据显示到液晶,并可通过UART修改EEPROM中的数据,所在章节14.4 14_t3:作业题3,以lesson10_4为基础实现可通过UART设定时间的交通灯示例,所在章节14.5 14_t4:作业题4,基于液晶、按键、EEPROM的密码锁示例,所在章节14.5 lesson15 (第15章): 15_1:用单次读写模式访问DS1302,并将日期时间显示在液晶上,所在章节15.3.4 15_2:用突发读写模式访问DS1302,并将日期时间显示在液晶上,所在章节15.3.5 15_3:DS1302实现简易电子钟,通过按键校时,所在章节15.5 lesson16 (第16章): 16_1:接收NEC协议的红外编码并将用户码和键码显示到数码管上,所在章节16.3 16_2:控制DS18B20测量温度并将温度值显示到液晶上,所在章节16.4 16_t2:作业题2,用遥控器控制步进电机正反转,所在章节16.5 16_t4:作业题4,带温度显示的电子钟,所在章节16.5 lesson17 (第17章): 17_1:将模拟输入通道0、1、3的电压值显示到液晶上,所在章节17.4 17_2:由按键控制DA输出可调电压值,所在章节17.6 17_3:由按键控制DA输出可变化的波形,所在章节17.7 17_t3:作业题3,可调频率的信号发生器,所在章节17.8 lesson18 (第18章): 18_1:RS485基本示例,接收任意数据帧并添加回车换行后送回,所在章节18.1 18_2:基于RS485的Modbus通信示例,支持寄存器读写操作,所在章节18.3 18_t3:作业题3,基于Modbus协议实现电子钟校时,所在章节18.4 lesson19 (第19章): 19_1:多功能电子钟例程,所在章节19.4
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值