精华内容
下载资源
问答
  • 2020-03-02 16:55:17

    串口中断服务函数详解
    void USART1_IRQHandle(void) //串口1中断服务程序
    {
    u8 Res;
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
    Res =USART_ReceiveData(USART1); //读取接收到的数据

    	if((USART_RX_STA&0x8000)==0)//接收未完成(判断USART_RX_STA的第15位是否为0,不为0时说明Res!=oxoa即接受没完成)
    		{
    		if(USART_RX_STA&0x4000)//接收到了0x0d,当if(Res==0x0d)USART_RX_STA|=0x4000;才执行该语句,“此次”的执行中断服务函数Res接受最后一个字符,正常情况下Res=oxoa)
    			{
    			if(Res!=0x0a)USART_RX_STA=0;//(如果Res!=0x0a)接收错误,重新开始
    			else USART_RX_STA|=0x8000;	//(Res=0x0a接收完成了,USART_RX_STA的第15位为1)
    			}
    			
    		else //还没收到倒数第二个字节0X0d
    			{	
    			if(Res==0x0d)USART_RX_STA|=0x4000;//如果接收到了倒数第二个字节0X0d,令USART_RX_STA的第14位为1,
    			else
    				{
    				USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;//接收数据字节,数组从0到199
    				USART_RX_STA++;//每接收一次加1
    				if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
    				}		 
    			}
    		}   		 
     } 
    

    }
    提示:0x0d和0x0a在ASCII码表里面表示\r和\n,分别表示回车和换行。如果串口接收方收到这两个字符,就会结束当前行的显示,开始从下一行的左端开始显示。

    更多相关内容
  • stm32之串口使用和串口中断

    千次阅读 2021-03-21 00:55:50
    串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,其通讯协议可分层协议层和物理层。物理层规定通信协议中具有机械、电子功能的特性,...

    1.定义

    串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,其通讯协议可分层为协议层和物理层。物理层规定通信协议中具有机械、电子功能的特性,从而确保原始数据在物理媒体的传播;协议层主要规定通讯逻辑,统一双方的数据打包、解包标准。通俗的讲物理层规定我们用嘴巴还是肢体交流,协议层规定我们用中文还是英文交流。下面分析一下串口通讯协议的物理层和协议层。

    2.通信基础

    1.通讯结构
    串口通讯的物理层的主要标准是RS-232标准,其规定了信号的用途、通讯接口及信号的电平标准,其通讯结构如下:
    在这里插入图片描述

    在设备内部信号是以TTL电平标准传输的,设备之间是通过RS-232电平标准传输的,而且TTL电平需要经过电平转换芯片才能转化为RS-232电平,RS-232电平转TTL电平也是如此。
    2.电平标准
    根据使用的电平标准不同,串口通讯可分为 RS-232标准 及TTL标准,具体标准如下:
    在这里插入图片描述

    在电子电路中常使用TTL的电平标准,但其抗干扰能力较弱,为了增加串口的通讯距离及抗干扰能力,使用RS-232电平标准在设备之间传输信息,经常使用MA3232芯片对TTL电平及RS-232电平进行相互转换。

    3.数据传输方式:
    A同步:
    传输以数据块为核心,在一个数据块内,字符间无间隔,接受发送同步,有sclk时钟,双方sclk连在一起,提供同步
    特点:效率高,无间隔
    B异步:
    以字符为传输单位,每发一个字符,都得发送一个起始位,(告诉对方我开始发了)结束发送停止位。(我发完了)
    特点:效率低,间隔任意

    4.串口数据包组成
    起始位、数据位(8位或者9位)、奇偶校验位(第9位)、起始停止位(1,15,2位)、波特率设置

    5.速率类型:
    比特:每秒传输的二进制位
    波特:每秒传输的码源个数(串口常用)

    注:这俩本质上其实是差不多的

    6.通信类型
    串行:一个一个传输 如:fsmc
    特点:占用资源多,速度慢,看干扰强
    并行:多个一起传输 如:spi usart
    特点:占用资源少,速度快。抗干扰能力弱,距离近

    7.通信方式
    单工:数据传输只支持数据在一个方向上传输;如:打印机

    半双工:允许数据在两个方向上传输。但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;它不需要独立的接收端和发送端,两者可以合并一起使用一个端口。如:对讲机,spi
    全双工:允许数据同时在两个方向上传输。因此,全双工通信是两个单工通信方式的结合,需要独立的接收端和发送端。如:spi,usart
    在这里插入图片描述

    8.概念补充
    1.数据包
    串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备得RXD接口,在协议层中规定了数据包的内容,具体包括起始位、主体数据(8位或9位)、校验位以及停止位,通讯的双方必须将数据包的格式约定一致才能正常收发数据。

    2.波特率
    由于异步通信中没有时钟信号,所以接收双方要约定好波特率,即每秒传输的码元个数,以便对信号进行解码,常见的波特率有4800、9600、115200等。STM32中波特率的设置通过串口初始化结构体来实现。
    3.起始和停止信号
    数据包的首尾分别是起始位和停止位,数据包的起始信号由一个逻辑0的数据位表示,停止位信号可由0.5、1、1.5、2个逻辑1的数据位表示,双方需约定一致。STM32中起始和停止信号的设置也是通过串口初始化结构体来实现。
    4.有效数据
    有效数据规定了主题数据的长度,一般为8或9位,其在STM32中也是通过串口初始化结构体来实现的。
    5.数据校验
    在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、 0 校验(space)、 1 校验(mark)以及无(noparity)。这些也都可以在串口初始化结构体中实现的。
    在这里插入图片描述

    3.USART简介

    在这里插入图片描述

    USART(通用同步异步收发器)是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。有别于 USART 还有一个UART,它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART。USART 在 STM32 应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一USART 通信接口连接电脑,用于在调试程序是可以把一些调试信息“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、如果出错哪具体哪里出错等等。

    4.串口结构体参数

    在这里插入图片描述

    5.串口相关函数

    void USART_Init //初始化函数
    (USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
    void USART_Cmd //串口使能函数
    (USART_TypeDef* USARTx, FunctionalState NewState);
    void USART_ITConfig //中断配置函数
    (USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);
    void USART_SendData //串口发送函数
    (USART_TypeDef* USARTx, uint16_t Data);
    uint16_t USART_ReceiveData //串口接收读取函数
    (USART_TypeDef* USARTx);
    FlagStatus USART_GetFlagStatus //获取相应的串口标志位
    (USART_TypeDef* USARTx, uint16_t USART_FLAG);
    ITStatus USART_GetITStatus //中断状态位获取
    (USART_TypeDef* USARTx, uint16_t USART_IT);
    在这里插入图片描述

    6.串口配置

    1.配置时钟:gpio,串口,引脚复用
    2.配置gpioA9,10结构体
    3.配置串口结构体
    4.初始化,打开串口
    5串口发送函数配置
    在这里插入图片描述
    附上参数.c文件代码

    
    
    #include "stm32f10x.h"
    #include "usart.h"
    
    void usart_init(void)
    {
    
    	GPIO_InitTypeDef  gpioinitStructure;//结构体变量定义,结构体定义要在时钟之前
    
    	USART_InitTypeDef usartinitStucture;
    	
    	
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE );
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//配置gpio,串口,串口复用时钟
    
    
    //先配置tx输出引脚io(pa9)
    gpioinitStructure.GPIO_Pin  =GPIO_Pin_9;//选择引脚
    gpioinitStructure.GPIO_Speed=GPIO_Speed_50MHz;//选择电平大小,初始状态无电平
    gpioinitStructure.GPIO_Mode =GPIO_Mode_AF_PP;//用推挽输出
    
    GPIO_Init(GPIOA,&gpioinitStructure );//端口初始化
    //再配置rx输出引脚io(pa10)
      gpioinitStructure.GPIO_Pin =GPIO_Pin_10;
    gpioinitStructure.GPIO_Speed=GPIO_Speed_50MHz;//选择电平大小,初始状态无电平
    
    	gpioinitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    
    GPIO_Init(GPIOA,&gpioinitStructure );//再次端口初始化,因为过程相同且都是gpio所以不用再定义
    
    	//串口结构体的配置
    usartinitStucture.USART_BaudRate								=115200;//波特率
    
    usartinitStucture.USART_HardwareFlowControl			=USART_HardwareFlowControl_None;//无限流
    usartinitStucture.USART_Parity				          =USART_Mode_Rx  |  USART_Mode_Tx;//输入输出模式
    usartinitStucture.USART_WordLength							=USART_Parity_No;//无校验位
    usartinitStucture.USART_StopBits								=USART_StopBits_1;//一个停止位
    usartinitStucture.USART_Mode										=USART_WordLength_8b;//有效数据长度8bit
    
    USART_Init(USART1,&usartinitStucture);//串口1初始化
    USART_Cmd(USART1,ENABLE);//打开串口1
    
    
    

    7.串口中断配置

    1.配置时钟:gpio,串口,引脚复用
    2.串口中断组选择
    3.配置gpioA9,10,串口结构体与初始化
    4.串口与中断控制器联系配置
    5.打开串口
    6.串口发送函数配置

    .c文件

    #include "stm32f10x.h"
    #include "usart.h"
    
    void usart_init(void)//串口发送接收和串口中断配置
    {
    
    	GPIO_InitTypeDef  gpioinitStructure;//结构体变量定义,结构体定义要在时钟之前
    
    	USART_InitTypeDef usartinitStucture;
    	NVIC_InitTypeDef  NVICinitStucture;
    
    	
    	//1.串口中断组的选择
    	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);
    	
    	//2.打开gpio,引脚复用和串口时钟
    	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
    	RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE );
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//配置gpio,串口,串口复用时钟
    
    
    //3.先配置tx输出引脚io(pa9)
    gpioinitStructure.GPIO_Pin  =GPIO_Pin_9;//选择引脚
    gpioinitStructure.GPIO_Speed=GPIO_Speed_50MHz;//选择电平大小,初始状态无电平
    gpioinitStructure.GPIO_Mode =GPIO_Mode_AF_PP;//选择输出方式,用推挽输出
    
    GPIO_Init(GPIOA,&gpioinitStructure );//端口初始化
    //4.再配置rx输出引脚io(pa10)
      gpioinitStructure.GPIO_Pin =GPIO_Pin_10;
    	gpioinitStructure.GPIO_Speed=GPIO_Speed_50MHz;//选择电平大小,初始状态无电平
    
    	gpioinitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    
    	GPIO_Init(GPIOA,&gpioinitStructure );//再次端口初始化,因为过程相同且都是gpio所以不用再定义
    
    	//5.串口结构体的配置
    usartinitStucture.USART_BaudRate								=115200;//波特率
    
    usartinitStucture.USART_HardwareFlowControl			=USART_HardwareFlowControl_None;//无限流
    usartinitStucture.USART_Parity				          =USART_Mode_Rx  |  USART_Mode_Tx;//输入输出模式
    usartinitStucture.USART_WordLength							=USART_Parity_No;//无校验位
    usartinitStucture.USART_StopBits								=USART_StopBits_1;//一个停止位
    usartinitStucture.USART_Mode										=USART_WordLength_8b;//有效数据长度8bit
    
    USART_Init(USART1,&usartinitStucture);//串口1初始化
    //6.串口和中断控制器联系配置
    USART_ITConfig(USART1, USART_IT_RXNE,ENABLE );
    
    //7.打开串口1
    USART_Cmd(USART1,ENABLE);
    
    //8.串口中断控制器结构体配置与初始化
    	NVICinitStucture.NVIC_IRQChannel									=USART1_IRQn;//中断通道,选择串口中断
    	NVICinitStucture.NVIC_IRQChannelPreemptionPriority=1;//配置中断优先级
    	NVICinitStucture.NVIC_IRQChannelCmd								=ENABLE;//使能打开
    	NVICinitStucture.NVIC_IRQChannelSubPriority				=1;//配置中断子优先级
    
    
    
    	NVIC_Init(&NVICinitStucture);//串口结构体初始化
    
    }
    void USARTSendByte(USART_TypeDef* USARTx, uint16_t Data)//串口发送字符函数封装
    {
    		 USART_SendData(USARTx, Data);//串口1发送字符0
    		 while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);//如果数据寄存器空标志位为空,则已经成功发送数据跳出
    }
    void USARTSendstr(USART_TypeDef* USARTx,char*str)//串口发送字符串函数封装
    {
    		uint16_t i=0;
    		do
    		{
    		USARTSendByte(USARTx,*(str+i));//串口发送字符函数封装
    		i++;
    
    		}while(*(str+i)!='\0');
    		
    		
    while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET);//如果数据寄存器空标志位为空,则已经成功发送数据跳出
    //检测字符串用tc,检测字符用txc
    }
    
    
    int fputc(int ch,FILE *f)//串口更改printf实现向电脑输出,这边只用单个字符的但函数进行多次调用
    {
    			 USART_SendData(USART1,(uint8_t) ch);//串口1发送字符
    			while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//如果数据寄存器空标志位为空,则已经成功发送数据跳出
    			return   ch;
    }
    int fget(int ch,FILE *f)//串口更改scanf函数实现向电脑接收一个数据
    {
    			while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);//如果数据寄存器空标志位为空,判断数据是否接受成功
    
    //接受用rxne,输入用txe
    	return (int)USART_ReceiveData(USART1);
    
    	
    }
    

    main函数中断服务函数

    在这里插入图片描述
    注:这里不用清除中断标志位也行

    展开全文
  • 三种方式:查询,中断,DMA 通用同步异步收发器(USART)提供了一种灵活的方法来与使用工业标准NR 异步串行数据格式的外部设备之间进行全双工数据交换。 USART利用分数波特率发生器提供宽范围的波特率选择。 它支持...
  • 51单片机串口中断功能的设置

    千次阅读 2021-01-15 16:07:43
    既然和外界需要“交互”,就必须使用“中断”功能,所以一般串口中断是配合使用的。 在总结串口使用方法之前需要对一些基本概念进行理解 第一. 关于波特率(baud rate)的解释,网上有很多文章,以我个人的肤浅...

    51单片机的串口功能就是和外界进行通讯,所谓的“外界”也就是与单片机进行交互的媒介,最常用的就是我们经常使用的计算机、平板或者其他设备(比如另一个单片机配合显示模块使用)。

    既然和外界需要“交互”,就必须使用“中断”功能,所以一般串口和中断是配合使用的。

    在总结串口使用方法之前需要对一些基本概念进行理解

    第一. 关于波特率(baud rate)的解释,网上有很多文章,以我个人的肤浅理解觉得说得是这样一回事儿:

    西方某大国正在经历总统换届选举,选来选去没有选出个像样的,公民们有意见,非要到国会进行“抗议(0元购)”,一下子来了7680口,有的人还拿着枪,有长的有短的,还有扛炮的!眼看着要乱,警察和抗议者达成协议,进来可以但是为了保证秩序,不能一下子都进来,需要分批进入,根据法律,拿枪的也不犯法,为了保证安全,需要对进场的人进行监视,尤其是带枪的(只限短款,扛炮的就先等等吧,几百年了这地方就被烧了一回,这次得谨慎点)。规定:每组只限2个人,每批包含4组,每组相距等同的距离,一次只能进入1批。根据带枪与否划分“风险级别”,两个人都带枪入场的为最高风险,两个人都不带枪的为最低风险,两个人其中之一带枪且带枪的人走在前面的为次级风险,两个人其中之一带枪且带枪的人走在后面的为三级风险。同时,不能光进不出,前门进后面出,进多少就得出多少,后门根据前门进入的人数统计需要出去的人数,每批之间的间隔时间并不固定,谁还没想在议长的椅子上坐会儿呢?

    上面的例子中那2个人中的每个人就可以看成是计算机系统中的“位”,而2个人为一组就可以看成是通信领域中的“码元”,因为带枪与否是两种状态,所以共组成了四种状态,就是例子中的“风险级别”。

    好了,现在有了这些概念就可以研究下面的概念了:

    位:计算机系统中一个二进制数,0或者1,上面的例子中那2个人中的每个人就可以看成是计算机系统中的“位”

    码元:一个二进制数是由若干个“位”构成的,而码元就是这个指定的二进制数,也就是说码元包含若干个二进制位,可以是1位,2位,或者3位,至于到底是几位是根据功能要求人为指定的,叫做“调制”,码元是传输信息的基本单位。上面的例子中每个小组就是一个“码元”

    字节(字符):计算机系统存储单元的一个基本单位就是字节,一个字节包含8个位(bit),上面的例子中每1批就是一个字节,每批包含4组总共8个人

    帧:通用异步接收发送方式(UART)中把特定的一组二进制数称为“帧”,这组特定的二进制数是由“开始位”,“数据位”,“奇偶校验位”,“停止位”依次连接而成的,等同于上面例子中的每批,在进出“国会”的时候,需要前后被两个警员夹在中间,前面一个警员就是“开始位”,末尾一个警员就是“停止位”,这里省去“奇偶校验位”,这“串”起来的2个警员再加上这1批中的8个人就是1“帧”。

    比特率:单位时间内传输的二进制位的数量,单位 bit/s,等同于上面例子中统计每小时总共进去多少人

    调制速率:单位时间传输码元的数量,等同于上面例子中统计每小时总共进去多少组

    波特率:应该被称作调制速率,简称调制率,单位是波特(baud),可见,所谓波特率就是调制速率,对应的也是上面例子中的组数

    公式:D=调制速率(波特率),R=比特率,L=每个码元中的比特(位)数,M=码元的状态数(上面的例子,带枪和不带枪2种情况(位)就构成4种风险级别(状态))

    D=\frac{R}{L}=\frac{R}{\log_2M}

    调制速率(波特率)与比特率的关系

    比特率 = 调制速率(波特率)x 码元(单个调制状态)对应的二进制位数

    不同的码元可以包含不同的位数,位数越多能分辨的不同状态的数量就越多,例如如果码元包含1个位,则只能分辨2种状态,如果码元包含2个位,则共能分辨4种状态,如果是包含3位呢,就共能分辨8种状态,可见,包含的位数越多,状态的分辨率越高,其实状态的总数就是2的N次方,N就是码元中包含的“位”数。至于一个码元要包含多少个二进制位,根据功能由设计者指定(你说了算!技术学到这儿是不是有点当家做主的感觉?)。

    如果码元就包含1个二进制位,则比特率就等于调制速率(波特率),被称为“两相调制”;如果码元就包含2个二进制位,共四种状态,则比特率就等于调制速率(波特率)X2,被称为“四相调制”;如果码元就包含3个二进制位,共8种状态,则比特率就等于调制速率(波特率)X3,被称为“八相调制”。

    最后问个问题,总共7680名抗议者要“有序抗议”国会,要求一天8小时“抗议完毕”,那么每小时要进出多少人?又是多少组呢?总共7680名抗议者,每组2人,每批4组,每批配备2名警员,每批一共10人,要让7680名抗议者“有序抗议”国会,配上警员的人数总共进出的人数达到9600(这个数字熟悉吗?),8小时抗议完毕,每小时要进出1200人,每小时600组,每小时60批(加上警员),结果中的1200人就等同于“位”的概念,600组就等同于“调制速率(波特率)”的概念,60批就等同与“字节(字符)”的概念

    第二. 有了前面的“国会抗议”事件,相信大家对比特率,波特率,调制速率都有了个了解,接下来的问题是:在异步串口通讯中为什么要保证发送方与接收方的波特率相同,答案包括两个方面:

    (1)单片机的“调制速率(波特率)”是如何确定的
             51 单片机中的“调制速率(波特率)”就是比特率,即每秒传送的位数,单位bit/s(位/秒)

    (2)“调制速率(波特率)”设置的意义
             单片机工作时必须根据内部或者外部设置的时钟基准对多种任务进行协调,对于串口通讯的操作同样少不了使用时钟基准作为时间参照,这个问题涉及到“采样”的概念,请参考博文串口波特率问题的处理,里面讲得很清楚,其实就是为了同步采样频率。另外,从文中也可以推算出“波特率”与“采样频率”、“机器频率”、“振荡频率”的关系,首先,“采样频率”=16X“波特率”,“采样频率”=“机器频率”,如果以12分频(12T)为准,“振荡频率”=12X“机器频率”,所以“振荡频率”=12X16X“波特率”;从周期的角度来看,“波特周期”=16X“采样周期”,“采样周期”=“机器周期”,“机器周期”(12T分频)=12X“震荡周期”,所以“波特周期”=16X12X“振荡周期”,明白了各个频率之间的关系就自然能理解后面介绍的初值问题

    第三. 51单片机异步串行通讯(UART)功能的使用

    与51单片机其他功能的实现类似,要使用串口中断功能就必须包含三个步骤:1. 设置+赋值  2. 中断设计

    设置和赋值操作因单片机型号的不同而不完全相同,但是原理是相似的,举一反三即可。这里用到的芯片是STC12C2052AD

    (1)设置+赋值

    这一步就是设置与串口和中断功能相关的寄存器以指定单片机的工作状态

    设置“辅助寄存器(Auxiliary Register)” AUXR
    AUXR可以设置定时器、串口传输的分频,这一设置决定了“机器频率”与“振动频率”的关系

    其中通过设置“T0x12”和“T1x12”分别设置定时器T0和T1的分频,默认为0即12分频
    其中通过设置“UART_M0x6”设置串口的分频,默认为0即12分频

     

    设置“串口控制寄存器(Serial Control Register)”SCON
    通过设置SCON可以指定波特率发生器的时钟基准


    SM0/SM1/SM2三个位的设置可以指定波特率发生器的时钟基准

    SM0SM1模式描述波特率时钟基准
    000半双工状态,发送接收8位数据,使用移位寄存器f_osc/12
    011全双工状态,发送10位数据定时器1的溢出率/PCON寄存器SMOD位
    102全双工状态,发送11位数据f_osc/16或者f_osc/32
    113全双工状态,发送11位数据定时器1的溢出率/PCON寄存器SMOD位








    SM0(serial mode bit0):串口模式0移位寄存器
    SM1(serial mode bit1):串口模式1,8位通用异步接收可变时钟基准寄存器
    SM2(serial mode bit0):多处理器协同通讯设置位,
                                               在模式0下SM2无效,配置模式0时SM2应该设置为0
                                               在模式1下,SM2用来检测接收过程中的有效“结束位”,当SM2=1时,仅当检测到有效“结束位”后,RI才被激活
                                               在模式2和3下,SM2用来激活“多处理器协同通讯”
    REN(reception enable):串口接收功能的使能位,REN=1:允许串口接收;REN=0:禁止串口接收
    TB8:在模式2和3中,TB8用来存储发送数据的第9位
    RB8:在模式2和3中,RB8用来存储接收数据的第9位
    TI(transimission interrupt):发送中断标志位,在模式0中,当第8位发送后由硬件置1;在模式1~3中,当“结束位”发送后由硬件置1,TI必须由软件置0
    RI(reception interrupt):接收中断标志位,在模式0中,当第8位接收后由硬件置1;在模式1~3中,当“结束位”接收后由硬件置1,RI必须由软件置0
    模式0:以固定的波特率工作在半双工状态
                 通过RxD管脚发送和接收8位数据,在数据发送与接收过程中通过TxD管脚输出移位时钟,波特率设置为12分之1的振荡频率
    模式1:以可变的波特率工作在全双工状态
                 传输过程中数据为10位,1个起始位+8个数据位+1个结束位,在数据接收过程中,结束位被存储在RB8位中
                 波特率的值取决于定时器1的溢出率和“电源控制寄存器”中SMOD位的设置值(这部分在后面介绍初值问题时有讲解)
    模式2:以固定的波特率工作在全双工状态
                 传输过程中数据为11位,1个起始位+8个数据位+1个可编程位+1个结束位,在数据接收过程中,可编程位被存储在RB8位中,
                 在数据发送过程中,可编程位被存储在TB8位中
                 波特率的值为32分之1的振荡频率或者16分之1的振荡频率,取决于“电源控制寄存器”中SMOD位的设置值
    模式3    以可变的波特率工作在全双工状态(波特率)
                 此模式与模式2相同,只是波特率是可变的,波特率的值取决于定时器1的溢出率和“电源控制寄存器”中SMOD位的设置值

     

    设置“定时器模式控制寄存器(Time Mode Control Register)” TMOD
    当在SCON寄存器设置了模式1或者3时则指定定时器1作为波特率发生器的时间基准,因此需要通过TMOD对定时器1进行设定

    TMOD各个位的设置意义不在此处详谈,可以参考数据手册上对定时器设置的内容
    一般使用定时器1工作在模式2作为波特率发生器(高四位的设置:GATE=0, C/T=0, M1=1, M0=0, 第四位设置为0)模式2为“自动填装定时器”,自动填装的意思就是用定时器的低8位TL1计时,当溢出时将高8位TH1的数值自动填装到低8位TL1
    (TH1:定时器1的高8位;TL0:定时器1的低8位)

     

    问题:“填装”的是什么值?
    这就要引出定时器的初值设置问题,至于什么是初值和实现怎样的功能请参考之前我写的一篇文章,51单片机硬件定时器设定的初值问题,如果知道了初值的概念和怎样设置初值,就应该考虑定时器、初值和波特率的关系以便正确使用串口功能,之前讲过,51 单片机中的“调制速率(波特率)”就是比特率,即每秒传送的位数,单位bit/s(位/秒),为了保证传输的正确性,每个位又被采样分频设置成若干个检测点,也就是说1个位被检测若干次,取其中指定的几次进行比较以确定数据传输是正确的,这样的采样分频设置可以是16采样(每位检测16次)、32采样(每位检测32次)或者64采样(每位检测64次),而每一个检测点即采样点就意味着定时器需要计数溢出一次,这里注意每个检测点不是定时器计数一次,而是计数溢出一次,而定时器计多少数后溢出就需要我们为定时器指定“初值”,这就是指定“初值”的原因!如果采用32次采样设置,波特率和定时器计数溢出频率的关系就可以用如下公式表示

    Baud=\frac{f_{overflow}}{32}

    Baud:波特率,这个值是预先知道的,我们可以在各种波特率值中选择一个(问题又来了,为什么波特率是选择出来的,而不是自己指定的?大家可以自行寻找答案)

    f_overflow:定时器的计数溢出频率

    当设置相应寄存器用定时器1的模式2作为波特率发生器时,使用的是低8位作为定时器,高8位和低8位在最初都被设置为初值,但高8位不参与计时,只是存储初值(当低8位计时溢出时,高8位自动再将初值传送给低8位,这样每次就不用重复设置初值了)。低8位作为定时器从初值开始计数直到超过最大值255时就发生了1次溢出,溢出后,存储在高8位的初值自动加载到低8位中重新开始计数,这样就可以知道在单位时间内(1秒)定时器一共“溢出”多少次,就是“溢出率”即f_overflow。既然提到“率”就必须和时间联系在一起,既然溢出率就是溢出的次数,而溢出的次数又是定时器计数造成的,因此就必须知道定时器每1次计数用了多少时间,在51单片机中,定时器每计数一次所经过的时间就是一个机器周期(看到这儿也应该理解“机器周期”的概念了),所以从计时到溢出所用的时间就等于T=NxM,N=从计时开始到溢出总共计数的次数,就是255-初值,其中255是8位定时器最大计数值;M=每次计数所用的时间就是1个机器周期,所以单位时间的溢出次数即溢出率 f_overflow = 1/NxM,到这里就可以建立波特率和初值、机器周期的关系

    Baud = \frac{1}{32\cdot N\cdot M}

    定时器的计数频率即机器频率又与时钟基准频率(振荡频率)有关,这样又把波特率和时钟基准频率建立了联系,公式如下

    Baud=\frac{1}{32\cdot N }\cdot \frac{1}{M}=\frac{1}{32\cdot N }\cdot \frac{f_{osc}}{12}=\frac{f_{osc}}{32\cdot 12\cdot N }

    Baud:波特率

    f_osc:时钟基准频率,也是振荡频率,例如使用外部晶振12MHz,那么f_osc就是12MHz

    M=每次计数所用的时间就是1个机器周期,倒数就是机器频率,而定时器机器频率(f_timer)=振荡频率(f_osc)/12,原因是系统采用了12分频,意思是外部晶振每振动12次,定时器计数1次,为什么采用12分频而不是其他值呢?其实这个分频数可以选择但不能随意指定,可以选择例如2分频,4分频,8分频,或者其他值,选择分频可以通过指定相应的寄存器值来实现,这里不展开,可以参考相应的技术手册。选择不同的分频意味着使用不同的速度,分频数越高,速度越慢,想要提高速度可以选择1分频,还记得之前介绍的那个AUXR寄存器吗?就是用来干这个事情的

    在实际计算波特率的初值时,还需要考虑另外一个参数,就是SMOD,这个参数是一个叫“电源控制寄存器(PCON)”中的一个位,通过设置SMOD,可以实现不同波特率的取值

     

    设置“电源控制寄存器(Power Control Register)” PCON

    SMOD=0,波特率以32分频(即每一位采样32次)(以32分频为例,具体参考技术手册)
    SMOD=1,波特率采样频率提高1倍

    最终波特率公式如下

    Baud=\frac{2^{smod}\cdot f_{osc}}{32\cdot 12\cdot N }=\frac{2^{smod}\cdot f_{osc}}{32\cdot 12\cdot \left (255-TH1 \right ) }

    Baud:波特率

    f_osc:时钟频率即振荡频率

    TH1:存储在定时器1高8位的初值

    SMOD:PCON寄存器的SMOD位(0:32分频;1:16分频)

    在实际计算中波特率是事先选择的定值,例如4800,9600等,通过上面公式视为了计算初值,例如波特率选择为 4800 bit/s,使用12分频的外部12MHz晶振,SMOD=1,则初值 TH1约等于243

    到这里就把选择指定波特率并且利用定时器1作为波特率发生器的设置和初值计算问题说完了

    为了正确使用串口还不得不用到中断处理,当系统接收到或者发送出需要的数据时,通过中断处理就可以实现系统和外界的交互,因此还必须设置和中断相关的寄存器

     

    设置“中断使能寄存器(Interrupt Enable Register)” IE

    中断使能寄存器(IE)可以按位赋值,所谓“按位”的意思就是可以单独指定EA的值,比如形如 EA=xxx,所谓“使能”就是开关的意思
    EA:总中断使能,想要使用中断功能,就必须将EA设置为1,否则任何中断都不能用
    ES:串口中断使能,想要使用串口中断功能,就必须将ES设置为1
    EPCA_LVD:PCA模块、低压检测中断
    EADC_SPI:ADC、SPI中断
    ET1:定时器1的中断使能
    EX1:外部中断 INT1 使能
    ET0:定时器0的中断使能
    EX0:外部中断 INT0 使能

    需要使用串口功能时,需要将 EA设置为1,将 ES设置为1

     

    (2)中断

    除了几个必须要进行设置的特殊功能寄存器外,还有一个寄存器也比较重要,就是SBUF,全程“串口数据缓冲器(Serial Data Buffer)”在通讯中无论是外界向单片机通过串口写入数据,还是外界通过串口读取单片机中的数据,都必须使用SBUF作为中转站,在使用时,把SBUF放置在中断处理函数中

    另外,在中断处理函数中需要指定中断类型为“串口中断”,通过指定“中断代号码”来实现,因为系统中断可以不同的处理程序触发的,比如定时器,外部中断,所以需要指定是哪个处理程序触发的,采用中断号来区分,实现串口中断处理程序的中断号为 4。

    串口中断处理函数的格式是  void 函数名() interrupt 4 {中断处理程序}

    中断处理程序的编写包括
    1. SBUF赋值
    2. 发送标志TI、接收标志RI在程序中清0(单片机发送数据后TI自动置1,单片机接收数据后RI自动置1,在程序中清0后等待下一次发送、接收数据)

    具体的程序示例我就不再写了,网上有很多,这里主要是把关于串口中断功能的相关设置总结一下,同时也就几个概念作出解释以便理解,本人也是初学者,如果有误还请见谅,指出,一同进步。

     

     

    展开全文
  • 笔记 学习51单片机串口中断

    千次阅读 2021-05-15 17:11:56
    单片机的串口通信功能是比较常用的功能。 80C51的串行口 我在学习的过程中,觉得SBUF的使用方法是最难的,于是对...当发送数据时,写“SBUF=A”,程序执行完这条语句便自动开始将串口发送寄存器中的数据一位位串口

    单片机的串口通信功能是比较常用的功能。在这里插入图片描述
    在这里插入图片描述
    80C51的串行口
    我在学习的过程中,觉得SBUF的使用方法是最难的,于是对着这个图和资料一步步理解,才搞明白一点“A=SBUF”和“SBUF=A”的意思。
    51单片机通过特殊功能寄存器SBUF对串行接收或串行发送寄存器进行访问,两个寄存器共用一个地址99H,但在物理上是两个独立的寄存器。当接收数据时,写“A=SBUF”,单片机会自动将串口接收寄存器中的数据取走给A;当发送数据时,写“SBUF=A”,程序执行完这条语句便自动开始将串口发送寄存器中的数据一位位从串口发送出去。这些知识可以在书籍上面找到。
    在这里插入图片描述
    在这里插入图片描述
    对定时器和串口初始化

    void  uasrinit()
    {
    	TMOD=0X20;//选择为定时器1模式,工作方式1,仅用TR1打开启动。
    	TH1=0xfa;      //波特率位4800   晶振频率为11.0592MHz
    	TL1=0Xfa;	
    // PCON=0x80;       //把SMOD=1,该状态下串口方式1,2,3的波特率加倍
    	TR1=1;//打开定时器	
      SM0=0;
      SM1=1;    //串口通信方式1,10位异步收发(8位数据)
      REN=1;     //打开接收
      ES=1;      //串口中断打开	
    	EA=1;       //打开总中断
    }
    

    中断程序

    void uasr() interrupt 4
    {
    	 int a;
    	a=SBUF;
    	RI=0;          //接收中断,与发送中断类似
    	SBUF=a;
    	while(!TI);
    	TI=0;         //发送中断标志,在方式1,2,3中由内部硬件置1,不清零就会一直发送。
    }
    

    全部程序

    #include "reg52.h"			 //此文件中定义了单片机的一些特殊功能寄存器
    #include <intrins.h>
    typedef unsigned int u16;	  //对数据类型进行声明定义
    typedef unsigned char u8;
    void  uasrinit()
    {
    	TMOD=0X20;//选择为定时器1模式,工作方式1,仅用TR1打开启动。
    	TH1=0xfa;      //波特率位4800   晶振频率为11.0592MHz
    	TL1=0Xfa;	
    // PCON=0x80;       //把SMOD=1,该状态下串口方式1,2,3的波特率加倍
    	TR1=1;//打开定时器	
      SM0=0;
      SM1=1;    //串口通信方式1,10位异步收发(8位数据)
      REN=1;     //打开接收
      ES=1;      //串口中断打开	
    	EA=1;       //打开总中断
    }
    void main()
    {
    	uasrinit();
    	while(1);
    }
    
    void uasr() interrupt 4
    {
    	 int a;
    	a=SBUF;
    	RI=0;          //接收中断,与发送中断类似
    	SBUF=a;
    	while(!TI);
    	TI=0;         //发送中断标志,在方式1,2,3中由内部硬件置1,不清零就会一直发送。
    }
    

    程序运行后的效果
    在这里插入图片描述
    也可以让单片机固定发送指定内容

    unsigned char flag,a,i;
    unsigned char code table[]="I get ";
    void init()
    {
    	TMOD=0X20;//选择为定时器1模式,工作方式1,仅用TR1打开启动。
    	TH1=0xfd;      //波特率位9600
    	TL1=0Xfd;
    //	ET1=1;//打开定时器0中断允许
    	
    	EA=1;//打开总中断
    	TR1=1;//打开定时器	
      SM0=0;
      SM1=1;    //串口通信方式1,10位异步收发(8位数据)
      REN=1;     //打开接收
      ES=1;      //串口中断打开	
    }
    void main()
    {	
      init();              //初始化
    	while(1)
    	{
    		if(flag==1)
    		{
    			ES=0;
    			for(i=0;i<6;i++)
    			{
    				SBUF=table[i];
    				while(!TI);
    				TI=0;
    			}
    			SBUF=a;
    			while(!TI);
    			TI=0;
    			ES=1;
    			flag=0;
    		}
    	}
    }
    void ti1() interrupt 4
    {
    		RI=0;
    	a=SBUF;
    	flag=1;
    }
    
    

    效果
    在这里插入图片描述
    该程序案例来自郭天祥的《51单片机C语言教程》
    总结:波特率很重要,在使用串口通信的之前一定要明白单片机的晶振频率。之前的学习因为波特率没有匹配正确,导致输出一段乱码。

    展开全文
  • 51单片机定时器、串口中断

    千次阅读 2021-01-05 19:08:46
    文章目录MCS-51功能单元一、定时器&计数器二、并行口&串行口三、中断系统 ...使计数值或定时值满足自己的要求,需预先将数据寄存器赋值,称为初值设定,中断中也要重新设定初值。 定时器和计数器本质
  • 从单片机到嵌入式开发——(6) 定时器与串口中断 在上文中我们讲到了基本的中断定义和外部中断的使用方法。在本次的 标准的51单片机有5个中断源:两个外部中断、两个定时器/计数器中断。具体如下: 优先级 中断源...
  • 并不是说不使能串口接受中断就无法接收数据,只是为了在串口接收数据的时候防止其程序打扰串口数据的接收,所以跑到中断中去接收数据。 不使用串口接收中断的情况下,数据会到DR,然后你及时把DR的数据读出来,不然...
  • STM32F407串口中断配置

    2021-09-17 16:27:35
    花费了很久,发现用库函数去访问发送完成和接收完成的标志会出问题,改成了直接访问寄存器对应的,终于实现串口中断的通信。至于什么库函数不行,lz还没有发现原因。 串口中断适合用于发送数据较少的情况,...
  • 目录一、USART、串口通信与中断方式简介USART简介串口通信简介中断方式简介二、实验内容与实验过程1、实验内容2、实验过程2.1 代码准备2.2 代码修改2.3 烧录程序2.4 运行结果三、总结四、参考链接 一、USART、串口...
  • 串口通信与中断

    千次阅读 2021-06-20 10:22:18
    首先TMOD确定定时器1的工作方式,双八位(因为串口是这样的,具体不清楚),然后在控制寄存器打开TR1(即启动定时器1),在中断允许位那里关闭定时器1中断,如果后面不用串口中断可以直接管总中断,最好还是关相应...
  • #include <STC15F2K60S2.H> #define FOSC 12000000 //晶振频率 #define BAUD 9600 //设置波特率 unsigned char ruart(); //串口接收一个字节数据 void tuart(unsigned char trdate... //串口发送一个字节数据.
  • 允许串口中断当单片机接收到一帧数据后,RI会置1,向CPU申请中断,若之前有中断允许,则产生了中断,进入中断服务程序.当然,单片机发送完一帧数据,TI也会置1,同样会产生中断!一般我们在发送数据时要关中断,因为一般你不用...
  • 相较于纯串口中断的收发占用单片机资源更少,受环境影响更小。发送同样可以采用DMA发送,但作为从机的发送处理也更方便,发送DMA的配置也很好解决,因此这里更改实验。逻辑上可能存在数据阻塞以及覆盖现象,但在...
  • 51单片机默认使用定时器1作为串口通信的波特率发生器、定时器1中断通信,串口与定时器1冲突,在遇到定时器不够用的时候可以用定时器2
  • 三种方式:查询,中断,DMA 通用同步异步收发器(USART)提供了一种灵活的方法来与使用工业标准NR 异步串行数据格式的外部设备之间进行全双工数据交换。 USART利用分数波特率发生器提供宽范围的波特率选择。 它支持...
  • 一.串口通讯
  • 1、RETI:中断操作指令 这条指令的功能和RET指令相似,2条指令的不同之处是:本指令清除了中断响应时,被置1的MCS-51内部不可寻址的 “优先级生效”触发器清零。中断程序完成后,一定要执行一条RETI指令,执行这条...
  • 串口中断接收函数

    千次阅读 2018-12-04 23:18:09
    /* 用来实现读取接收FIFO中的数据 */ void ReceiveByteUart0(U8 ch) { U32 i; if(GetUartCmdFlag==1)return; // 完成读取 comRbuf[UartDataPointer]=ch;... // 串口有数据 if(UartDataPointer&gt...
  • 《8051单片机实战分析(以STC89C52RC例) | 01 - 点亮一个LED》 《8051单片机实战分析(以STC89C52RC例) | 02 - LED延时约5s闪烁》 《8051单片机实战分析(以STC89C52RC例) | 03 - LED流水灯》 《8051单片机...
  • 子函数:void serial() ...别的中断都是在某个I/O口低电平时产生中断,串口中断是在什么情况下产生呢? 首先,你要用软件允许中断,即 C语言中 EA = 1; //允许总中断 ES = 1; //允许串口中断 汇编中可用 SETB ...
  • 问题现象:STM32L432单片机MCU程序串口1,接收中断方式,发送采用查询方式。当使用SSCOM定时发送数据给MCU时,正常情况下,MCU收到什么就会回什么数据。如果使用100ms发送,MCU长时间测试都正常。如果使用1ms或者5ms...
  • 1、串口1初始化配置 /** * @brief USART GPIO 配置,工作参数配置 * @param 无 * @retval 无 */ void USART_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; ...
  • N76E003双串口中断配置、问题及解决方法 最近在调试N76E003串口0,串口1中断时,发现当串口0开启中断后,串口1中断无法正常工作,下面详细说说自己的办法。(我的问题原因是中断优先级造成的,取消串口1中断...
  • 利用stm32串口中断进行数码管显示

    千次阅读 2017-05-04 23:09:13
    串口通信一般有三种形式,即查询方式、中断方式和DMA方式...不用等在那儿,该干嘛干嘛,大大提高了效率,因此本次实验采用中断方式,将利用串口中断,在中断服务程序中读取串口输入的数值,然后在数码管上显示出该数值。
  • 这次项目用的是STM32H7的主控+cubemx+MDK做的开发,项目中使用到了FreeRTOS+lwip以及多个串口,且每个串口的波特率都是一个比较高的波特率(均在460800以上),与传统大家常用的9600及115200在调试...
  • 4.2 51单片机-中断

    2021-10-28 16:49:20
    4.2 中断 4.2.1 中断介绍 中断系统是使CPU具有对...微型机的中断系统一般允许多个中断源,当几个中断源同时向CPU请求中断,要求它服务的时候,这就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻
  • STM32单片机(3) 串口中断通信

    千次阅读 2014-08-06 00:56:03
    串口中断通信(软件延时方式)
  • 基于串口接收中断与发送中断完成的485通讯实例 优点:逻辑简单,响应快速。 缺点:容易受到单片机本身资源占用以及运行环境干扰的影响出现丢包情况。 对应程序初始化后在主循环运行Uart1_Communicate即可。 使用联合...
  • 没写博客的感悟:昨天没有写博客,...今天主要总结和复习三个知识点,NVIC中断优先级管理、串口通信、及串口通信的简单配置实例: 第一部分: NVIC中断优先级管理: 首先是中断分组,我们知道所用的CM3内核支持

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,958
精华内容 7,983
关键字:

串口中断的中断允许位为