精华内容
下载资源
问答
  • 2021-01-05 17:33:21

            串行口中断服务函数和其他中断本质上是一样的,达到特定的条件,向CPU申请中断,进入中断服务函数;

    我特意在郭天祥老师的书上找到了一句话:当数据被写入SBUF寄存器后,单片机自动开始从起始位发送数据,发送到停止位的开始时,由内部硬件将TI置1,向CPU申请中断,接下来可在中断服务程序中做相应处理,也可选择不进入中断。接收数据时 RI 同理。

             那么下面就有一个问题:串口中断是高电平触发还是上升沿触发?如果是高电平触发,多次响应时每次间隔时间是多久?

             先来引述我在书上看到的一段话:中断服务函数中查询TI 和 RI进行判别, 然后分别处理。因此,两个中断请求标志位均不能由硬件自动置位,必须通过软件清0,否则将出现一次请求多次响应的错误。此处的一次请求多次错误很明显是高电平触发的。

    更多相关内容
  • SBUF, TI/RI, ES

    千次阅读 多人点赞 2019-09-23 11:36:06
    这里来个小结,51单片机的一些关于串口通信的寄存器/锁存器。 首先放上一段代码,来自郭天祥的51单片机教程 功能是:向单片机发送一个字符(比如e),然后单片机返回字符串“ I get e”,串口通信。 #include...

    寒假过去一半了,这两天重新开始学习。这里来个小结,51单片机的一些关于串口通信的寄存器/锁存器。

     

    首先放上一段代码,来自郭天祥的51单片机教程

    功能是:向单片机发送一个字符(比如e),然后单片机返回字符串“ I get e”,串口通信。

    #include <reg52.h>
    #include <intrins.h>
    
    typedef unsigned char uchar;
    typedef unsigned int uint;
    uchar flag, a;
    uchar code table[]=" I get ";
    
    //串口初始化
    void Serial_Init()
    {
        TMOD = 0x20;    //设定T1定时器工作方式2
        TH1 = 0xfd;        //T1定时器装初值
        TL1 = 0xfd;        //T1定时器装初值
        TR1 = 1;        //启动T1定时器
        REN = 1;        //允许串口接收
        SM0 = 0;        //设定串口工作方式1
        SM1 = 1;        //同上
        EA = 1;            //开总中断
        ES = 1;            //开串口中断
    }
    void main()
    {
    
        Serial_Init();
    
        while(1)
        {
            if(flag)
            {
                uchar i;
                ES = 0;//先关闭串口中断防止干扰
                for(i=0; i<7; i++)
                {
                    SBUF = table[i];
                    while(!TI);//即等待发送完成,因为发送完成后TI由硬件置位
                    TI = 0;//清零以进行下一次发送
                }
                SBUF = a;//串行发送时,CPU向SBUF写入数据,sbuf的容量很大
                while(!TI);
                TI = 0;
    
                ES = 1;
                flag=0;
            }
        }
    }
    
    void ser() interrupt 4        //串口中断,接收,a相当于接收缓存
    {
        RI = 0;//接收完成后RI由硬件置1,中断里面清零以进行下一次接收
        a = SBUF;//串行接收时,CPU从SBUF读出数据
        flag = 1;
    }

     

     

    1.SBUF

    引用百科:

    全称:serial data buffer
    串行数据缓冲器
    串行口中有两个缓冲寄存器 SBUF,一个是发送寄存器,一个是接收寄存器,在物理结构 上是完全独立的。它们都是字节寻址的寄存器 ,字节地址均为99H。
    这个重叠的地址靠读/写指令区分:串行发送时,CPU向SBUF写入数据,此时99H表示发送SBUF;串行接收时,CPU从SBUF读出数据,此时99H表示接收SBUF。单片机串口程序参考。
     
        之前学习的时候对SBUF一知半解,只是抄了代码,看了效果。这两天重新学习后得到一些新的认识。
    首先是百科中提到的,串行口中有两个缓冲寄存器SBUF,一个是发送寄存器,一个是接收寄存器,在物理结构上是完全独立的。它们都是字节寻址的寄存器,字节地址均为99H。代码段中 SBUF=a 或者 SBUF = table[i] 都是CPU向SBUF写入数据,同时表示此时是发送状态, a=SBUF 是CPU从SBUF读出数据,同时表示此时是接收状态。也即0x99H这个重叠的地址靠读/写指令区分。
        另外SBUF的容量很大,至少可以放200字节数据(200个字符)
     
    2.TI/RI
     
    首先是Scon的 百科
    SCON (Serial Port Control Register 在51单片机中代表这是串口控制寄存器
    scon控制寄存器,它是一个可位寻址的专用寄存器,用于串行数据的通信控制,单元地址是98H,其结构格式如下:
     
    SCONSM0SM1SM2RENTB8RB8TIRI
    位地址9FH9EH8DH9CH9BH9AH99H98H
    其中
    TI:发送中断标志位
    可寻址标志位。方式0时,发送完第8位数据后,由硬件置位,其它方式下,在发送或停止位之前由硬件置位,因此,TI=1表示帧发送结束,TI可由软件置0。
    RI:接收中断标志位
    可寻址标志位。接收完第8位数据后,该位由硬件置位,在其他工作方式下,该位由硬件置位,RI=1表示帧接收完成。
    注:在串口中断处理时,TI、RI都需要软件置0,硬件置位后不可能自动清0,此外,在进行缓冲区操作时,需要ES=0,以防止中断出现。
     
    代码中SBUF = table[i]  即发送后有 while(!TI)  即等待发送完成,因为发送完成后TI由硬件置位,然后 TI = 0  软件清零以进行下一次发送
    RI也是一样,进入中断是因为PC通过串口向单片机发送了信息,单片机接收完成后RI由硬件置1, RI = 0 由软件清零以进行下一次接收。
     
    3.ES
    参考 这里,ES是中断允许寄存器IE的第5位(IE^4),表示 串行口中断允许(ES=1充许,ES=0禁止)。代码中首先ES=0,关闭串口中断防止干扰,先把要发的数据放到SBUF,全部放完后再ES=1,使能串口中断。
     
    唔,如果昨晚效率高些就能早点总结完这个然后看can通信的代码了。。这里给自己小结下(其实是参考百科等资料把看懂的表达出来),对下一步有帮助。
     
    51和stm32各有长短,stm32给nrf24l01的配置比较麻烦。。
     
    嗯,新年快乐,马上快乐~
     
     

    转载于:https://www.cnblogs.com/Cmfvacks-IsLjj/p/3537274.html

    展开全文
  • 串行发送完毕后,将在标志位 TI 置 1,同样,当收到了数据后,也会在 RI置 1。无论 RITI 出现了 1,只要串口中断处于开放状态,单片机都会进入串口中断处理程序。在中断程序中,要区分出来究竟是发送引起的...
  • stm32F1以及51单片机串口通信详解 1、连线: 如图所示:我们先记住四条线,分别是电源线,地线,以及发送接收线 既然两个单片机要通讯,那么一个发送一个接收,那么肯定是一个单片机的发送端连接到另一个单片机的...

    stm32F1以及51单片机串口通信详解

    在这里插入图片描述
    在这里插入图片描述

    1、连线: 如图所示:我们先记住四条线,分别是电源线,地线,以及发送和接收线
    既然两个单片机要通讯,那么一个发送一个接收,那么肯定是一个单片机的发送端连接到另一个单片机的接收端,就像两个人说话,一个用嘴说,一个用耳朵听,那么话语就是其中的抽象连线
    2、数据的传输格式
    (1)核心思想:就是低位先发高位后发(也就是说先发低位比如01234567位先发0,如果是二进制数据11100100先发0)
    (2)数据的本质是什么?答案:电平状态
    比如:
    发送一个 0xE4 这个数据,用二进制形式表示就是 0b11100100,在 UART 通信过程中,是低位先发,高位后发的原则,那么就让 TXD首先拉低电平,持续一段时间,发送一位 0,然后继续拉低,再持续一段时间,又发送了一位 0,然后拉高电平,持续一段时间,发了一位 1……一直到把 8 位二进制数字 0b11100100全部发送完毕。
    (3)数据传输格式是什么?答案:数据包
    每个数据包包含1个起始位,5至9个数据位(一般是8位),可选的奇偶校验位(一般不设置)和1或1.5或2个停止位(一般是1位),协议如下:
    在这里插入图片描述
    在这里插入图片描述
    如图:我们可以很清晰明了的看出数据包包含4种数据位类型,终结起来就是:起始>>数据>>校验>>停止
    其实是和我们生活中做事是一样的总要有个开始和结束,然后包含事情的内容以及检查一下做的事到底对不对,当然啦,现实中的事情往往复杂的多,毕竟很多事往往无疾而终……
    3、数据传输的动力:波特率
    那么波特率的作用是什么?答案:其实说白了就是告诉单片机多久发送一个数据包
    比特率是每秒钟传输二进制代码的位数,单位是:位/秒(bps)。
    在电子通信领域,波特(Baud)即调制速率,指的是有效数据讯号调制载波的速率,即单位时间内载波调制状态变化的次数。
    波特率表示每秒钟传送的码元符号的个数,它是对符号传输速率的一种度量,它用单位时间内载波调制状态改变的次数来表示,1波特即指每秒传输1个符号。
    数据传输速率使用波特率来表示。单位bps(bits per second),常见的波特率9600bps、115200bps等等,其他标准的波特率是1200,2400,4800,19200,38400,57600。举个例子,如果串口波特率设置为115200bps,那么传输一个比特需要的时间是1/115200≈8.68us。
    在这里插入图片描述
    以上就是串口通信的原理,其实总结起来一句话:
    以波特率为动力发送数据包!!!(so easy)
    原理有了那么具体怎么实现传输数据的功能呢?就像道理大家都懂就是不会做事情
    下面我们以51单片机以及stm32单片机为例,分别写一下串口通讯的驱动代码:
    4、软件驱动:
    4.1 51单片机:
    4.1.1 80C51串行口的结构
    在这里插入图片描述
    有两个物理上独立的接收、发送缓冲器SBUF,它们占用同一地址99H ;接收器是双缓冲结构 ;发送缓冲器,因为发送时CPU是主动的,不会产生重叠错误。
    4.1.2 串行口的控制寄存器(SCON)
    用以设定串行口的工作方式、接收/发送控制以及设置状态标志:
    在这里插入图片描述
    SM0和SM1为工作方式选择位,可选择四种工作方式:
    在这里插入图片描述
    SM2,多机通信控制位,主要用于方式2和方式3。当接收机的SM2=1时可以利用收到的RB8来控制是否激活RI(RB8=0时不激活RI,收到的信息丢弃;RB8=1时收到的数据进入SBUF,并激活RI,进而在中断服务中将数据从SBUF读走)。当SM2=0时,不论收到的RB8为0和1,均可以使收到的数据进入SBUF,并激活RI(即此时RB8不具有控制RI激活的功能)。通过控制SM2,可以实现多机通信。在方式0时,SM2必须是0。在方式1时,如果SM2=1,则只有接收到有效停止位时,RI才置1。
    REN,允许串行接收位。由软件置REN=1,则启动串行口接收数据;若软件置REN=0,则禁止接收。
    TB8,在方式2或方式3中,是发送数据的第九位,可以用软件规定其作用。可以用作数据的奇偶校验位,或在多机通信中,作为地址帧/数据帧的标志位。在方式0和方式1中,该位未用。
    RB8,在方式2或方式3中,是接收到数据的第九位,作为奇偶校验位或地址帧/数据帧的标志位。在方式1时,若SM2=0,则RB8是接收到的停止位。
    TI,发送中断标志位。在方式0时,当串行发送第8位数据结束时,或在其它方式,串行发送停止位的开始时,由内部硬件使TI置1,向CPU发中断申请。在中断服务程序中,必须用软件将其清0,取消此中断申请。
    RI,接收中断标志位。在方式0时,当串行接收第8位数据结束时,或在其它方式,串行接收停止位的中间时,由内部硬件使RI置1,向CPU发中断申请。也必须在中断服务程序中,用软件将其清0,取消此中断申请。
    看起很复杂,但是实际上没有啥东西:比如,我们选择方式1,那么只需将sm0=0,sm1=1,记忆:01,使能位REN=1;TI和RI就是中断标志位而已,我们需要做的就是软件清零而已,TB8通常不用
    SCON=0X50;这是什么意思?解析成2进制就是0000 0000 0101 0000
    我们主要看低8位:0101的前面两个数代表方式1,sm2=0,并使能,接收到的数据直接进入Buff并且使RI=1,这个时候需要我们在中断函数里将标志位清0即可
    4.1.3 PCON功率控制寄存器中只有一位SMOD与串行口工作有关 :
    在这里插入图片描述
    SMOD(PCON.7) 波特率倍增位。在串行口方式1、方式2、方式3时,波特率与SMOD有关,当SMOD=1时,波特率提高一倍。复位时,SMOD=0。
    这里不要想那么复杂只需要做一件事情:PCON=0X80; 这条语句应该可以看得懂
    4.1.4波特率的计算(用波特率计算器)
    方式0的波特率 = fosc/12
    方式2的波特率 =(2SMOD/64)· fosc
    方式1的波特率 =(2SMOD/32)·(T1溢出率)
    方式3的波特率 =(2SMOD/32)·(T1溢出率)
    T1 溢出率 = fosc /{12×[256 -(TH1)]}
    在单片机的应用中,常用的晶振频率为:12MHz和11.0592MHz。所以,选用的波特率也相对固定。常用的串行口波特率以及各参数的关系如表所示。
    在这里插入图片描述
    4.1.5串口如何使用?
    (1)确定串行口控制(编程SCON寄存器);
    (2)确定T1的工作方式(编程TMOD寄存器);TMOD=0X20;
    (3)计算T1的初值,装载TH1、TL1;
    (4)启动T1(编程TCON中的TR1位);
    4.1.6定时器知识点:
    定时器/计数器的结构
    定时器/计数器的实质是加1计数器(16位),由高8位和低8位两个寄存器组成。TMOD是定时器/计数器的工作方式寄存器,确定工作方式和功能;TCON是控制寄存器,控制T0、T1的启动和停止及设置溢出标志。
    在这里插入图片描述
    定时器/计数器的工作原理
    计数器输入的计数脉冲源
    系统的时钟振荡器输出脉冲经12分频后产生;
    T0或T1引脚输入的外部脉冲源。
    计数过程
    每来一个脉冲计数器加1,当加到计数器为全1(即FFFFH)时,再输入一个脉冲就使计数器回零,且计数器的溢出使TCON中TF0或TF1置1,向CPU发出中断请求(定时器/计数器中断允许时)。如果定时器/计数器工作于定时模式,则表示定时时间已到;如果工作于计数模式,则表示计数值已满。
    定时应用
    用作定时器:此时设置为定时器模式,加1计数器是对内部机器周期计数(1个机器周期等于12个振荡周期,即计数频率为晶振频率的1/12)。计数值N乘以机器周期Tcy就是定时时间t 。
    计数运用
    用作计数器:此时设置为计数器模式,外部事件计数脉冲由T0或T1引脚输入到计数器。每来一个外部脉冲,计数器加1。但单片机对外部脉冲有基本要求:脉冲的高低电平持续时间都必须大于1个机器周期。
    工作方式寄存器(TMOD)
    在这里插入图片描述
    GATE:门控位。
    GATE=0时,只要用软件使TCON中的TR0或TR1为1,就可以启动定时器/计数器工作;(即需要一个启动条件)
    GATE=1时,要用软件使TR0或TR1为1,同时外部中断引脚也为高电平时,才能启动定时器/计数器工作,即需要两个启动条件。
    C/T :定时/计数模式选择位。
    C/T =0为定时模式; C/T =1为计数模式。
    M1M0:工作方式设置位。
    计数器工作方式选择
    M1 M0 工 作 方 式 功 能 说 明
    0 0 方式0 13位计数器
    0 1 方式1 16位计数器
    1 0 方式2 自动重装8位计数器
    1 1 方式3 定时器0:分成两个8位
    定时器1:停止计数
    定时器/计数器的控制
    控制寄存器TCON
    TCON的低4位用于控制外部中断,已在前面介绍。TCON的高4位用于控制定时器/计数器的启动和中断申请。其格式如下:
    在这里插入图片描述
    TF1(TCON.7):T1溢出中断请求标志位。T1计数溢出时由硬件自动置TF1为1。CPU响应中断后TF1由硬件自动清0。TR1(TCON.6):T1起/停控制位。1:启动 0:停止
    TF0(TCON.5):T0溢出中断请求标志位,其功能与TF1类同。
    TR0(TCON.4):T0起/停控制位。1:启动 0:停止
    定时器/计数器的工作方式
    方式0
    方式0为13位计数,由TL0的低5位(高3位未用)和TH0的8位组成TL0的低5位溢出时向TH0进位,TH0溢出时,置位TCON中的TF0标志,向CPU发出中断请求。
    在这里插入图片描述
    方式1
    方式1的计数位数是16位,由TL0(TL1)作为低8位、TH0(TH1)作为高8位,组成了16位加1计数器 。
    方式2
    方式2为自动重装初值的8位计数方式。
    在这里插入图片描述
    在方式2下,当计数器计满255(FFH)溢出时,CPU自动把TH 的值装入TL中,不需用户干预。因此特别适合于用作较精确的脉冲信号发生器。
    方式3
    在这里插入图片描述
    方式3只适用于定时器/计数器T0,定时器T1方式3时相当于TR1=0,停止计数。
    工作方式3将T0分成为两个独立的8位计数器TL0和TH0 。
    注意:1、EA:访问外部程序存储器控制信号。
    2、ES:串口中断允许控制位。
    TF1:其值位1时,表示定时器T1计满溢出。
    TF0:其值位1时,表示定时器T0计满溢出。
    TR1:为1是定时器T1开始计数;0时不计数。
    TR0:为1是定时器T0开始计数;0时不计数。
    IE1:当发生外部中断1时其值为1。
    IE0:当发生外部中断0时其值为1
    以上的知识都掌握后就可以写程序啦:
    4.1.7程序代码:
    PC和单片机通信:

     #include<reg52.h>
       typedef unsigned char uchar;
         void  myuart()
        {
        SCON=0X50; //设置为工作方式1 ,既然是方式一,自然要确定波特率,设置定时器1
        	TMOD=0X20;                  //8位重装载
        	PCON=0X80;
        	TH1=0xFA; TL1=0XFA;          //设置波特率为9600
        	ES=1;						//打开通信中断
        	EA=1;						//打开总中断
        	TR1=1;					//打开计数器
        }
         
        void main(void)
        {
         myuart();
        	while(1);
        }
         
        void iuart() interrupt 4
        {
        	uchar receiveData;
        	receiveData=SBUF;//出去,接,收到的数据
        	RI = 0;//清除接收中断标志位
        	SBUF=receiveData;//将接收到的数据放入到发送寄存器
        	while(!TI);			 //等待发送数据完成
        	TI=0;						 //清除发送完成标志位
        }
    
    

    这里还需要注意一点是什么?也就是SBUF,如果是接收数据就从SBUF里读出数据来receiveData=SBUF;如果想发送,就往SBUF里写数据SBUF=receiveData;
    4.2 stm32F103 库函数
    4.2.1、简介:
    STM32F103ZET6 有 3 个 USART(通用同步和异步收发器) + 2 个 UART(通用异
    步收发器),分别是 USART1,USART2,USART3 和 UART4,UART5
    4.2.2、USART 和 UART 有什么区别呢?
    当进行异步通信时,这两者是没有区别的。区别在于 USART 比 UART 多了同步
    通信功能,同步通信需要 STM32 提供时钟来同步。
    这个同步通信功能可以把 USART 当做 SPI 来用,比如用 USART 来驱动 SPI 设
    备。我们用得最多的是全双工异步通信功能
    在这里插入图片描述
    在这里插入图片描述
    4.2.2.1、 我们需要设置的数据有通信速率,数据字长,奇偶检验位,停止位。一个典 型的设置是 115200 波特率,8 位数据,无奇偶校验,1 位停止位。
    这个设置在固件函数库里面,我们是通过设置 USART_InitStructure 结构体,
    然后调用 USART_Init 函数来实现的:
    USART_InitStructure.USART_BaudRate = 115200; //设置通信波特率为 115200
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; //设置通信数据格式为 8 位数据
    USART_InitStructure.USART_StopBits = USART_StopBits_1; //设置停止位为 1 位
    USART_InitStructure.USART_Parity = USART_Parity_No ; //设置为无奇偶校验
    /* 设置为无硬件流控制,即无 CTS/RTS 控制 /
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    /
    设置发送使能,接收使能 */
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    USART_Init(USART1, &USART_InitStructure); //调用 USART_Init,把上面的参数分别设置进 USART
    的控制寄存器 USART1->CR1,USART1->CR2,USART1->CR3
    USART_Cmd(USART1, ENABLE); //使能串口
    4.2.2.2、 上面 USART_Init 函数配置了 USART1 的数据通信格式,但串口能工作的前提是需要配置相应的TX,RX引脚,这个是通过GPIO_Configuration函数来配置的:
    void GPIO_Configuration(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //打开 USART1 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //打开 AFIO 时钟
    /* 配置 USARTx_Tx 为复用推挽输出 /
    GPIO_InitStructure.GPIO_Pin = GPIO_TxPin;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOx, &GPIO_InitStructure);
    /
    配置 USARTx_Rx 为输入悬空 */
    GPIO_InitStructure.GPIO_Pin = GPIO_RxPin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOx, &GPIO_InitStructure);
    }
    4.2.2.3、 配置好 USART1 使用的引脚,数据通信格式,下面就可以收发数据了,USART_GetFlagStatus 函数可以读取收发状态等,读取状态标志可以是以下几个:
    在这里插入图片描述
    4.2.2.4、 发送数据示例:
    USART_SendData(USART1, ‘a’); //发送一个字符 a
    4.2.2.5、 接收数据示例:
    u16 RxData;
    RxData = USART_ReceiveData(USART1); //从 USART1 接收数据到 RxData 变量
    FlagStatus USART_GetFlagStatus();//获取状态标志位
    void USART_ClearFlag();//清除状态标志位
    ITStatus USART_GetITStatus();//获取中断状态标志位
    void USART_ClearITPendingBit();//清除中断状态标志位

    ***4.2.2.6、下面是串口通信 printf 程序里的主要功能,上电打印一串信息,把接收到的数
    据回显到 PC 上:
    /
    用 printf 打印一串信息到 PC 的超级终端或串口调试软件上 /
    printf("\n\rUSART Printf Example: retarget the C library printf function to the USART\n\r");
    while (1)
    {
    if(USART_GetFlagStatus(USARTx,USART_FLAG_RXNE)==SET) //判断是否有数据要接收
    {
    i = USART_ReceiveData(USARTx); //接收数据
    printf("%c\n\r",i&0xff); //回显到 PC 的超级终端或串口调试软件上
    }
    }
    4.2.2.7、 printf 的实现
    上面的 printf 是怎么实现的呢,这个是 C 标准库里定义的函数,我们是怎 样把它的输出重定向到串口的呢?
    我们知道 printf 是调用 fputc 函数来打印的,所以我们只要把 fputc 函数 重定义就可以了:
    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE f)
    PUTCHAR_PROTOTYPE
    {
    /
    调用 USARTx 发送一个字符
    /
    USART_SendData(USARTx, (u8) ch);
    /
    等待发送完成 /
    while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET)
    {
    }
    return ch;
    }
    另外还要加上头文件
    #include “stdio.h”
    4.2.2.8、 串口配置的一般步骤
    (1)串口时钟使能,GPIO时钟使能:RCC_APB2PeriphClockCmd();
    (2)串口复位:USART_DeInit(); 这一步不是必须的
    (3)GPIO端口模式设置:GPIO_Init();
    (4)串口参数初始化:USART_Init();
    (5)开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
    NVIC_Init();
    USART_ITConfig();
    (6)使能串口:USART_Cmd();
    (7)编写中断处理函数:USARTx_IRQHandler();
    (8)串口数据收发:
    void USART_SendData();//发送数据到串口,DR
    uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
    (9)串口传输状态获取:
    FlagStatus USART_GetFlagStatus(USART_TypeDef
    USARTx, uint16_t USART_FLAG);
    void USART_ClearITPendingBit(USART_TypeDef
    USARTx, uint16_t USART_IT);
    4.2.2.9、 简单通信程序

    #include "stm32f10x.h"
    #include "sys.h" 
    #include "key.h"
    #include "led.h"
    #include "beep.h"
    #include "delay.h"
     
    void My_USART1_Init(void)
    {
     
    GPIO_InitTypeDef GPIO_InitStrue; 
    USART_InitTypeDef USART_InitStrue;
    NVIC_InitTypeDef NVIC_InitStrue; //定义结构体变量声明
     /*使能IO口和串口1*/
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);//①
        /*初始化I/O口*/
     
     GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP;//推挽复用输出
     GPIO_InitStrue.GPIO_Pin=GPIO_Pin_9;
     GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz;
      GPIO_Init(GPIOA,&GPIO_InitStrue);//②
     
     GPIO_InitStrue.GPIO_Mode=GPIO_Mode_IN_FLOATING;//下拉输入
     GPIO_InitStrue.GPIO_Pin=GPIO_Pin_10;
     GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz;
      GPIO_Init(GPIOA,&GPIO_InitStrue);//②
     /*串口初始化*/
     
     USART_InitStrue.USART_BaudRate=115200;//波特率
     USART_InitStrue.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//不用硬件复位
     USART_InitStrue.USART_Mode=USART_Mode_Tx|USART_Mode_Rx; //发送和接收模式
     USART_InitStrue.USART_Parity=USART_Parity_No;   //不用奇偶校验位
     USART_InitStrue.USART_StopBits=USART_StopBits_1;  //停止位1
     USART_InitStrue.USART_WordLength=USART_WordLength_8b; //8位数据
     
     USART_Init(USART1,&USART_InitStrue);//③
     
     USART_Cmd(USART1,ENABLE);//使能串口1
     
     USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启接收中断
     
     /*设置优先级分组*/
    
     NVIC_InitStrue.NVIC_IRQChannel=USART1_IRQn;  //通道为串口1
     NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE;     //分组使能
     NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=1; //抢占优先级为1(0-3)
     NVIC_InitStrue.NVIC_IRQChannelSubPriority=1;         //子优先级为1(0-3)
     NVIC_Init(&NVIC_InitStrue);
     
     
    }
    
    void USART1_IRQHandler(void)   //中断服务函数
    {
     u8 res;
      if(USART_GetITStatus(USART1,USART_IT_RXNE))//如果接收到了中断
     {
         res= USART_ReceiveData(USART1);    //变量=接收的数据
      
      LED_Init();BEEP_Init();
      BEEP=!BEEP;
      LED1=!LED1;
         USART_SendData(USART1,res);   //单片机将接收到的变量发送回PC端
      }
    }
     
     int main(void)
     { 
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置优先级分组为模式2,也就是说优先级都是2位的
     My_USART1_Init();  //初始化,坐等中断函数服务就行了
      while(1);
      
     }
    
    

    4.2.2.10、 原子printf函数实现:
    //加入以下代码,支持printf函数,而不需要选择use MicroLIB
    #if 1
    #pragma import(__use_no_semihosting)
    //标准库需要的支持函数
    struct __FILE
    { int handle;
    };

    FILE __stdout;
    //定义_sys_exit()以避免使用半主机模式
    _sys_exit(int x)
    { x = x; }

    //重定义fputc函数
    int fputc(int ch, FILE *f)
    {
    while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
    USART1->DR = (u8) ch;
    return ch;
    }
    #endif
    4.2.2.11、 原子的串行通信协议(重点,多项目可参考其思想):
    在这里插入图片描述
    程序如下:

    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
      {
      Res =USART_ReceiveData(USART1); //读取接收到的数据
      
      if((USART_RX_STA&0x8000)==0)//接收未完成(一开始肯定为真)
       {
       if(USART_RX_STA&0x4000)//接收到了0x0d(一开始肯定为假)
        {
        if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
        else USART_RX_STA|=0x8000; //接收完成了 (接收到了0x0d 0x0a)
        }
       else //还没收到0X0D
        { 
        if(Res==0x0d)USART_RX_STA|=0x4000;
        else
         {
         USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
         USART_RX_STA++;
         if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收   
         }   
        }
       }      
         }
    12、原子主函数:
      while(1)
     {
      if(USART_RX_STA&0x8000)
      {        
       len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
       printf("\r\n您发送的消息为:\r\n\r\n");
       for(t=0;t<len;t++)
       {
        USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
       }
       printf("\r\n\r\n");//插入换行
       USART_RX_STA=0;
      }else
      {
       times++;
       if(times%5000==0)
       {
        printf("\r\n 串口实验\r\n");
        printf("ALIENTEK\r\n\r\n");
       }
       if(times%200==0)printf("请输入数据,以回车键结束\n");  
       if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
       delay_ms(10);   
      }
     }  
     }
    
    展开全文
  • 51单片机串行通信原理

    千次阅读 2020-11-24 20:40:31
    51单片机串行通信原理计算机通信串行通信异步通信同步通信数据传送速率传输方向单片机串行口串行口特殊功能寄存器串行口控制寄存器SCON电源控制寄存器PCON 计算机通信 计算机通信:计算机与外部设备或计算机之间的...

    计算机通信

    计算机通信:计算机与外部设备或计算机之间的信息交换。基本的通信方式有两种。

    1. 并行通信:将传送数据字节的各位用多条数据线同时进行传送。优点:控制简单,传输速度快。缺点:由于传输线较多,长距离传送成本高且接收方的各位同时接受困难。
    2. 串行通信:所传送的数据各位按顺序一位一位地发送或接收。优点:传输线少,成本低。缺点:控制复杂。

    串行通信

    异步通信

    通信的发送与接收设备使用自己的时钟控制数据的发送和接收过程(两个时钟尽可能一致)。
    数据或字符是一帧一帧地传送的。先用一个起始位0表示字符的开始,然后是8位数据,规定低位在前,高位在后。其后是奇偶校验位,此位通过对数据奇偶性的检查,可用于判别字符传送的正确性(可省略)。最后是停止位,用以表示字符的结束。

    同步通信

    发送方时钟对接收方时钟的完全控制,保持位同步关系也保持字符同步关系。

    数据传送速率

    波特率: 每秒钟传送二进制代码的位数
    单位:位/秒,bps
    传输距离随传输速率增加而减少。
    调制解调器:由于距离太远时,要先采用调制器把数字信号转换位模拟信号,并加以放大在传送。在接收时,在用解调器把模拟信号转换成数字信号在送入计算机接口。

    传输方向

    单工:数据传输仅能沿一个方向
    半双工:数据传输可以沿两个方向,但要分时进行。
    全双工:数据可以同时进行双向输出


    单片机串行口

    内部硬件结构:两个物理上独立的接受、发送缓冲器SBUF。发送缓冲器只能写入不能读出。接收缓冲器只能读出不能写入。

    串行口特殊功能寄存器

    串行口控制寄存器SCON

    符号字节地址位名称位名称位名称位名称位名称位名称位名称位名称复位值
    SCON98HSM0/FESM1SM2RENTB8RB8TIRI0000 0000
    1. RI:接收中断标志位。在方式0时,接收完第8位数据时,RI由硬件自动置1。在其他方式中,串行接收到停止位时,该位置1。RI=1,表示一帧数据接收完毕,并申请中断,要求CPU从接收SBUF取走数据。RI必须用软件清0。
    2. TI:发送中断标志位。。在方式0时,发送完第8位数据时,TI由硬件自动置1。在其他方式中,串行发送停止位的开始时,该位置1。TI=1,表示一帧数据发送完毕,并申请中断,在 CPU响应中断后,在中断服务程序中向SBUF写入要发送的下一帧数据。TI必须用软件清0。
    3. RB8:接收的第9位数据。在方式1时,若SM2=0,RB8接收到的停止位。在方式0中。不使用RB8.
    4. TB8:发送的第9位数据。其值由软件置1或清0。在双机串行通信时,一般作为奇偶校验位使用;在多级串行通信中用来表示主机发送的是地址帧还是数据帧,TB9=1为地址帧,TB8=0为数据帧。在方式0和方式1中,不使用TB8。
    5. REN:允许串行接受位。由软件置1或清0。REN=1,允许串行口接收数据;REN=0,禁止串行口接收数据。
    6. SM2:多机通信控制位。在方式2和方式3时进行。如果SM2=1,则只有当接收到的第九位数据(REB)为1时,才使RI置1,产生中断请求,并将接收到的前8位数据送入SBUF,当接收到的第九位数据位0时,则将接收到的前8位数据丢弃;如果SM2=0,则将前8位数据送入SBUF中,并使RI置1。
    7. SM0/SM1:方式选择位
    SM0SM1工作方式功能说明波特率
    00方式08位同步移位寄存器常用于扩展I/O口fosc/12
    01方式110位URAT8位数据、起始位、结束位可变(由定时器控制)
    10方式211位URAT8位数据、起始位0、结束位1和奇偶校验位fosc/32或fosc/64
    11方式311位URAT8位数据、起始位0、结束位1和奇偶校验位可变(由定时器控制)

    fosc=晶振的频率。
    URAT=异步通信寄存器


    电源控制寄存器PCON

    符号字节地址位名称位名称位名称位名称位名称位名称位名称位名称复位值
    PCON87HSMODSMOD0POFGF1GF0PDIDL0xx1 0000

    仅SMOD、SMOD0两位与串口有关

    1. SMOD0:帧错位检测有效控制位。当SMOD0=1时,SCON寄存器中的SM0/FE位用于FE(帧错误检测)功能。当SMOD0=0时,SCON寄存器中的SM0/FE位用于SM0功能。
    2. SMOD:波特率选择位。(波特率倍增位):在方式2时,SMOD=1要比SMOD=0时的波特率加倍。

    波特率的设定与计算

    1. 方式0
      波 特 率 = f o s c 12 波特率=\frac{f_{osc}}{12} =12fosc
    2. 方式2
      波 特 率 = 2 S M O D 64 × f o s c 波特率=\frac{2^{SMOD} }{64} \times{f_{osc }} =642SMOD×fosc
      串行口工作在方式2时,波特率仅与SMOD位的值有关。
    3. 方式1和方式三
      波 特 率 = 2 S M O D 32 × 定 时 器 T 1 的 溢 出 率 波特率=\frac{2^{SMOD} }{32} \times{定时器T1的溢出率} =322SMOD×T1
      T1常设置为方式2定时,即8位重装入方式,并且不允许T1中断。可以避免软件重装初值带来的定时误差。
      定 时 器 1 的 溢 出 率 = 1 溢 出 周 期 = 1 ( 256 − X ) × T c y = f o s c 12 × ( 256 − X ) 定时器1的溢出率=\frac{1 }{溢出周期}=\frac{1}{(256-X)\times{T_{cy}}}=\frac{f_{osc}}{12\times{(256-X)}} 1=1=(256X)×Tcy1=12×(256X)fosc
      式中Tcy为系统机器周期;X为初值

    PC与多个单片机通信

    1. 采用RS-232标准总线通信
    2. 采用RS-422标准总线通信

    串口如何使用

    串行口工作之前,应对其初始化

    1. 确定T1的工作方式(TMOD);
    2. 计算T1的初值,装载TH1,TL1;
    3. 启动T1(TCON中的TR1位)
    4. 确定串行口控制(SCON)
      中断设置(IE,IP寄存器)
    展开全文
  • 串口通讯

    2020-03-28 20:41:33
    单片机与外部设备交换信息时,通常采用串行通讯和并行通讯
  • 用8051单片机串行口外接CD4094扩展8位并行输出口,8位并行口的各位都接一个发光二极管,要求发光管呈流水灯状态。 串行口方式0的数据传送可采用中断方式,也可采用查询方式,无论哪种方式,都要借助于TIRI标志。
  • 串口通讯
  • 单片机串行通信

    千次阅读 2020-08-07 12:11:42
    文章目录串行通信串行口控制器内部结构串行口控制寄存器工作方式0工作方式 1工作方式2工作方式 3 串行通信 计算机与外部设备的通信方式有两种,一是并通信、二是串行通信串行通信有:单工、半双工(常用)、全...
  • 哈哈哈罗各位同学,很高兴又大家见面了,继上次我们所聊的串口通信的一些概念,今天咱们来聊一下基于STC89C51/52系列单片机的串口硬件结构。 51单片机的串行口是一个可编程的全双工通信接口,基本结构如下图所示...
  • 哭求指点:中断实现串口异步通信--RI为何始终为0,并且接收不到数据?RI为何始终为0,并且接收不到数据?recv_buf[]始终不变,借不到数??请明白人指点,我快疯了!!!//////////////////////////////////////////...
  • 51单片机串口通信

    2021-01-06 04:54:53
    使用串口通信,需要对SCON、PCONTMOD三个特殊寄存器进行配置。 SCON 串口工作方式寄存器SCON(98H)的结构如下表所示: SCON 位 7 6 5 4 3 2 1 0 意义 SM0 SM1 SM2 REN TB8 RB8 TI RI SM2:多机通信控制...
  • 若用 while(TI==0)等待发送完成 当发送完成(TI=1)时,涉及 1)TI=1 跳出循环 while(TI==0) ; 2)TI=1 进入中断 两条指令的执行先后问题 一般认为 TI=1后的瞬间,先进行中断的调用过程,即,将TI清零; ...
  • beep bit p2.2 ;蜂鸣器定义org 00hjmp mainorg 23h ;串行中断入口地址jmp com_int ;串行中断服务程序;*********** 主程序开始 *******************org 30hmain: mov sp,#30h...
  • 串口通信实验

    千次阅读 2022-01-15 19:59:26
    串口通信实验
  • 串口通信

    2019-08-06 15:53:02
    串口特点
  • 51单片机系列--串口通讯

    千次阅读 2021-07-19 09:58:28
    串行通信和并行通信 串行通信和并行通信都是一种通信传输方式,都适用于计算机与计算机、计算机与单片机之间的数据通信,在传输中存在相互转换的关系。但是两者在使用上还是有着不同的: 一次传输的传输量不同 并行...
  • 例如:奇偶校验,前面发送八位数据码,第九位为验证码,第九位计算前面的二进制中有多少个1,如果1的个数是偶数,...在这里讲讲RI ,TI; RI : 接收中断位,当定时器1的时间到后,中断标志位RI置1,与定时器0中的...
  • 这条指令的功能RET指令相似,2条指令的不同之处是:本指令清除了中断响应时,被置1的MCS-51内部不可寻址的 “优先级生效”触发器清零。中断程序完成后,一定要执行一条RETI指令,执行这条指令后,CPU将会把堆栈中...
  • 通信的三种基本类型常用的通信从传输方向上可以分为单工通信、半双工通信、全双工通信三类。单工通信就是指只允许一方向另外一方传送信息,而另一方不能回传信息。比如电视遥控器、收音机广播等,都是单工通信技术。...
  • 单片机之串口通信

    2021-01-19 18:37:34
    串口通信是单片机一个重要的部分,单片机PC,单片机单片机之间的通信大都用串口。单片机的串口是全双工异步串口通信方式。通过TXD(P3.1)发送,RXD(P3.0)引脚接收输入。串口传送数据是一帧一帧发送的,它有四种...
  • 单片机串行传递数据

    2021-10-12 19:17:44
    串行传递数据结构图 TI和RI是发送接收数据标志位,发送完成以后TI标志位置1,接受完成以后RI标志位置1。 串行传递数据,模式一波特率计算方法 串行传递数据的波特率计算方法,SMOD1是PCON寄存器的最高位,也是第八...
  • 单片机串口通信

    千次阅读 2021-05-05 14:47:15
    串行传输:一位一位传输节省传输线,串行通信适合于远距离传送 串口通信协议: 串口通信协议是指规定了数据包的内容,内容包含了起始位、主体数据、校验位及停止位,双方需要约定一致的数据包格式才能正常收发数据的...
  • STC学习:串口通信

    千次阅读 2021-08-03 10:31:48
    程序设计目标:本实验实现的是红外单工方简单上下位机串口数据的发送与接收。单片机通过按键2、3调整发送的数据(0~F),按键1控制数据发送给上位机,并在串口助手的接收数据缓存区显示;上位机设定发送缓存区数据...
  • 51单片机之串口通信详解及代码示例

    千次阅读 2022-04-20 09:34:53
    串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信。 单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大的扩展了单片机的...
  • 单片机C51 - 串行通信原理及串口编程实验

    千次阅读 多人点赞 2016-09-07 10:42:00
    一、两种通信方式概念 1.并行通信 传输原理:并行通信时数据的各个位同时传送,以字节为单位并行传输优点:并行通信速度快,传输的数据宽度可以是1~128位...优点:串行通信传输线少,占用引脚资源少,成本低,适合远
  • 20.串行通信原理及操作流程

    千次阅读 2020-09-20 20:53:57
    通信有并行串行龄种方式,在单片机系统以及现代单片机测控系统中,信息的交换多采用串行通信的方式。 6.1.1并行通信方式 ​ 并行通信通常是将数据字节的各位用多条数据线同时进行传送,每一位数据都需要一条传输线...
  • 串口通信测试方法

    千次阅读 2021-05-20 11:43:33
    串口通信测试方法》由会员分享,可在线阅读,更多相关《串口...在PC机系统中都装有异步通信适配器,利用它可以实现异步串行通信。而且MCS-51单片机本身具有一个全双工的串行接口,因此只要配以电平转换的驱动电路...
  • 51单片机的串口通信

    千次阅读 2019-11-14 16:28:57
    1、实现现象:下载程序后打开串口调试助手,将波特率设置为4800,选择发送的数据就可以显示 在串口助手上 2、实验程序 #include "reg52.h" typedef unsigned int u16; typedef unsigned char u8; void ...
  • //之前用轮询方式实现了串口通讯,这里使用前后台系统结架构实现功能 int s; void UART_INT() interrupt 4//UART中断处理程序 { if(RI == 1)//如果收到数据 { RI = 0; s = SBUF;//将收到的数据读取出来 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,222
精华内容 1,288
关键字:

串口通信ti和ri

友情链接: dijkstra.rar