精华内容
下载资源
问答
  • 串口通讯(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函数中断服务函数

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

    展开全文
  • 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后等待下一次发送、接收数据)

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

     

     

    展开全文
  • #define DEBUG_USART_IRQ USART1_IRQn //串口中断的中断源 #define DEBUG_USART_IRQHandler USART1_IRQHandler 若要调用相关的中断功能,在NVIC中配置相关的中断优先级和中断号。 以下是中断函数(有每一步操作的...

    参考教程:野火 

    以串口1为例,在利用串口进行接受数据时,我们要对STM32进行串口的中断配置。

    先对进行宏定义(起个别名),方便移植:

    
    #define  DEBUG_USART_IRQ                USART1_IRQn        //串口中断的中断源
    #define  DEBUG_USART_IRQHandler         USART1_IRQHandler

    若要调用相关的中断功能,在NVIC中配置相关的中断优先级和中断号。

    以下是中断函数(有每一步操作的详细备注):

    //中断函数 
    static void NVIC_Configuration(void)
    {
    	/*定义一个名字为NVIC_InitStructure的结构体*/
      NVIC_InitTypeDef NVIC_InitStructure;
      
      /* 用NVIC_PriorityGroupConfig(NVIC_PriorityGroup_n)
    	                选择中断数量种类(n可取值0~4); */
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
      
      /* 配置USART为中断源 */
      NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
      /* 抢断优先级 (抢占优先级)*/
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
      /* 子优先级(响应优先级) */
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
      /* 使能中断(IQR通道使能) */
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      /* 根据指定的参数初始化NVIC寄存器*/
      NVIC_Init(&NVIC_InitStructure);
    }

    接着在串口配置中写入以下函数:

    	// 完成串口的初始化配置
    	USART_Init(DEBUG_USARTx, &USART_InitStructure);
    	
    	// 串口中断优先级配置
    	NVIC_Configuration();
    	
    	// 使能串口接收中断
    	USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
    				      //^^接收数据寄存器非空,接收到数据产生中断
    	
    	// 使能串口
    	USART_Cmd(DEBUG_USARTx, ENABLE);	    
    以下这段代码是存放在 stm32f4xx_it.c 文件中的,该文件用来集中存放外设中断服务函数。当我们使 能了中断并且中断发生时就会执行这里的中断服务函数。
    
    	//中断服务函数
    void DEBUG_USART_IRQHandler(void) 
    { 
    	
    	uint8_t ucTemp;
    	if (USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
    		{
    				ucTemp = USART_ReceiveData( DEBUG_USARTx );
    					USART_SendData(DEBUG_USARTx,ucTemp);
    		}
    }
    

    解释:1当外部设备(如串口调试助手)给单片机发数据时
    2单片机检测到接收数据寄存器非空:表示有数据
    3进中断服务函数调用USART_GetITStatus()再次检测标志位是否置1 防止产生误中断
    4再利用函数USART_ReceiveData()把数据放入变量ucTemp
    5最后利用函数USART_SendData()发送数据回来(回显功能)

    展开全文
  • 原标题:STC12C5A60S2 串口中断接收程序#define UART0_BUF_LEN 32 int UART1_Recv_count; //接收计数bit UART1_Overflow_Flag; //缓冲区满标志idata uchar UART1_Recv_BUF[UART0_BUF_LEN]; //串口接收缓冲区//串口...

    原标题:STC12C5A60S2 串口中断接收程序

    #define UART0_BUF_LEN 32 int UART1_Recv_count; //接收计数

    bit UART1_Overflow_Flag; //缓冲区满标志

    idata uchar UART1_Recv_BUF[UART0_BUF_LEN]; //串口接收缓冲区

    //串口初始化

    void Init_Uart()

    {

    UART1_Overflow_Flag=0;

    UART1_Recv_count=0;

    //22.1184M 晶振 115200波特率

    PCON &= 0x7f; //波特率不倍速

    SCON = 0x50; //8位数据,可变波特率

    BRT = 0xFA; //设定独立波特率发生器重装值

    AUXR |= 0x04; //独立波特率发生器时钟为Fosc,即1T

    AUXR |= 0x01; //串口1选择独立波特率发生器为波特率发生器

    AUXR |= 0x10; //启动独立波特率发生器

    ES = 1; //充许串口1中断

    }

    //

    /*

    说明:

    (1)如果缓冲区接收满了,则中断接收程序不在接收数据。UART1_Recv_count=32

    (2)如果接收到“回车符”、“换行符”,则中断不在接收数据。UART1_Recv_count={实际接收到的数据个数}

    以上2种情况触发后 UART1_Overflow_Flag标志位置为1,等待MAIN函数(主程序处理)

    */

    void UART1_Int(void) 4

    {

    if (RI == 1)

    {

    RI = 0;

    if(UART1_Overflow_Flag==0)

    {

    if(UART1_Recv_count

    {

    UART1_Recv_BUF[UART1_Recv_count++] = SBUF;

    if(SBUF=='\r' || SBUF=='\n')

    {

    UART1_Overflow_Flag=1;

    }

    }

    else

    {

    UART1_Overflow_Flag=1; // 关闭串口中断,停止接收

    }

    }

    2=~LED2;

    }

    }

    int main()

    {

    char i;

    TMOD=0x00;

    AUXR=0x00;

    LED1=0;

    LED2=1;

    Init_Uart();

    EA=1; //开总中断

    printf("System is start...\r\n");

    while(1)

    {

    if (UART1_Overflow_Flag==1) //串口中断数据接收完毕,开始处理

    {

    for(i=0;i

    printf("%c",UART1_Recv_BUF[i]);

    Appcall(UART1_Recv_BUF,UART1_Recv_count);

    printf("\r\n");

    UART1_Recv_count = 0; //缓存清零

    UART1_Overflow_Flag=0; //允许串口继续接收数据

    }

    }

    }

    小知识:

    [1]换行符、回车符的定义

    ASIC

    C语言编程描述

    回车符

    0a(13)

    \r

    换行符

    0d

    \n

    换行符、回车符的来历:

    在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做“回车”,告诉打字机把打印头定位在左边界;另一个叫做“换行”,告诉打字机把纸向下移一行。这就是“换行”和“回车”的来历,从它们的英语名字上也可以看出一二。

    后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。

    Unix系统里,每行结尾只有“”,即“\n”;

    Windows系统里面,每行结尾是“”,即“\n\r”;Mac系统里,每行结尾是“”。

    在ascii中,回车和换行是不同的字符。0x0A是回车,即光标移动到本行的最左面; 0x0D是换行,即光标移动到下一行。

    [2]常见的串口工具如何发生“换行符”

    bd130af972d5e330c8f529292e9209ab.gif

    在用串口工具发送数据时,如果勾选了发送新行,串口工具就会在数据尾部添加“换行符”

    [2] STC波特率计算

    STC单片机官网上有一个比较好用的波特率计算工具,大家都可以自己下载了使用。

    8eab4ae8c98659bf43e486b8cfc1f63c.png

    选择好晶振,波特率发生器、定时器时钟后, 该程序就可以自动生成代码了。非常方便。

    STC官网地址:http://www.stcmcu.com/

    [3]关于STC单片机独立波特率发生器的理解

    a. STC单片机有1个独立的波特率发生器,虽然用独立的波特率发生器就不需要用定时器了。但是要注意的时,独立波特率发生器和“晶振”频率还是有关的。

    b. 如果要串口的数据收发误码率较低,还是要选用 11.0592 、22.1184 这些晶振。

    b549bdff75fc1db4579c3ac3ddaf498f.png

    注意看上图,误码率为 0.00%

    c. 6M、 12M 、24M 这些晶振如果在里,是不建议用的

    d. 在STC单片机上,用 11.0592 晶振,是可以非常方便的上 115200 波特率高速传输的,这是普通的AT89S很难实现的。

    2735f1a5a62fef0a36d572cff16ebeca.png

    只要让单片机工作在1T的工作模式下,11.0592的晶振,也可以轻松跑到115200波特率。

    责任编辑:

    展开全文
  • 目录DMA通信原理DMA的基本介绍DMA工作原理STM32的DMA结构DMA的主要特性DMA寄存器列表DMA进行数据传输的必要条件中断实验练习STM32用HAL库点亮LED灯任务要求实验过程采用串口中断方式通信任务要求实验过程DMA实现串口...
  • 1.从轮询到中断很多同学都不喜欢用中断,而偏爱用轮询的操作方式。这是不是和我们的天性有关呢?每个人都喜欢一切尽在掌握中,肯定都不喜欢被打断。我们常常都有这样的经验:正在跟别人说一件事,然后...
  • 串口中断方式的发送过程是怎么回事? 有人问过这个问题: “用串口中断接收比较好理解,只要接收缓存接收到数据,标志位就会置位,然后进入中断服务程序读取接收缓存中的数据,但是在发送时,应该是在数据...
  • STM32串口中断+DMA接收不定长字符串

    千次阅读 多人点赞 2019-10-14 21:09:45
    STM32串口中断+DMA接收不定长字符串 硬件平台:stm32f103rct6(大容量产品) 软件环境:KEIL MDK+stm32f1固件库 串口:USART1 ----------------------------------------------------------------------------- 看了...
  • 一.串口通讯
  • 中断处理--串口中断

    千次阅读 2014-09-14 22:25:19
    本例实现通过中断来使用串口,流程:在程序中调用printf,它把数据放在DDR内存中的一个buffer中;使用6410的FIFO中断,当FIFO中的数据少于64位的时候(就是还没满),产生一个中断信号给CPU,在中断处理中从buffer中...
  • cc2530入门 与串口中断处理

    万次阅读 2016-05-05 17:26:19
    做毕业设计的时候用到了cc2530开发板,用协议栈编程实现智能家居的功能。现在总结一下:  先从Z_Stack的main()函数开始。 main函数在ZMain.c中,总体来说,...先引入一下概念性的东西: 端点(EndPoint):是协议栈应
  • 第七章MCS51的串行口 本章主要介绍串行通信概念及51系列单片机 的串行口问题,将具体介绍以下内容 计算机串行通信基础-基本概念标准接 51单片机串行口-串行口结构串行口的 控制寄存器串行口的工作方式应用举例 本章...
  • 本实验首先大家自身要有stm32cubemx基础配置,比如GPIO、中断串口、SPI等,FreeRTOS有相关的调用函数基础及调度任务的概念都需要提前理解。单独stm32cubemx或FreeRTOS网上很多,这里就不细说了。 第一步首先打开...
  • 在本系列的第四篇文章中,讲述了串口发送数据基本配置...串口接收数据主要通过中断来实现,中断概念在本系列的第三篇文章中提到过,这里再重复一下:中断有很多的触发方式,你在代码中先要设定好它的触发方式,待...
  • 1.0.2通信的几个专业性概念 (1)同步和异步 (2)双工 半双工,单工 (3)并行通信和串行通信 (4)电平信号和差分信号 1.1串行通信 (1)串口通信 (2)一种特定的通信协议,一般叫串口通信,串行通信,UART USART...
  • 文章目录一、中断介绍1.基础知识2.中断向量表3.中断过程二、CubeMX中断方式点灯1.题目要求2.CubeMX设置设置管脚设置时钟源配置时钟优先级生成工程3....4.先占优先级也就是抢占优先级,概念等同于51单片机
  • 中断概念2.中断的作用3.中断优先级二、实验题目要求1. 题目一2. 题目二三、中断方式点灯四、中断方式实现串口通信五、实验总结六、参考博客 一、中断简介 1.中断概念 整个中断过程分为三步 1.中断发生:当CPU在处理...
  • 没写博客的感悟:昨天没有写博客,...今天主要总结和复习三个知识点,NVIC中断优先级管理、串口通信、及串口通信的简单配置实例: 第一部分: NVIC中断优先级管理: 首先是中断分组,我们知道所用的CM3内核支持
  • 在我目前负责的项目,之前是使用串口接收中断来判断是否完成数据接收,项目的坑货前任最开始的方法是在串口接收中断里面清除标志,在微系统的数据处理里面对标志位++,判断如果两次没进到接收中断就认为接收数据完成...
  • 本文以经典的RS232串口通信来模拟收银台电脑与打印机之间的通信工作流程。 用笔记本电脑模拟收银台电脑,串口通信助手为上位机界面; 用STM32F103C8T6单片机作为打印机控制器; 用PL2303HX模块完成USB到TTL电平的...
  • 51单片机中断基本概念

    千次阅读 多人点赞 2020-07-31 10:11:47
    中断概念 为什么引入中断? 中断是为使单片机具有对外部或内部随机发生的事件实时处理而设置的,中断功能的存在,很大程度上提高了单片机处理外部或内部事件的能力。 中断系统特点: ①分时操作。CPU 可以分时为...
  • 串口、波特率等概念

    万次阅读 多人点赞 2018-06-09 17:00:53
    UART串口有着这样或者那样的优点,但新兴的USB接口的USB DFU功能可以更加有效替代串口来完成固件升级;性能优越的CAN总线,其硬件价格不断下降,而且CAN总线的MAC接口更多集成在最新MCU芯片上;CAN2.0B接口正在挤压着...
  • 中断优先级:二、HAL库中断点亮LED灯三、HAL库中断串口通信四、DMA1.概念2.STM32F103C8T6以DMA方式实现连续发送五、总结六、参考链接 一、中断 1.数据传输方式 (1)无条件传输:处理器不必了解外部设备状态,直接...
  • 二、串口及串口中断的配置: 三、stm32f4xx_it.h 的配置: 四、DMA的配置: 五、主函数 如果大家有什么问题,欢迎在下面评论交流! 串口部分的详解:梳理STM32F429之通信传输部分---NO.1 串口通讯 DMA直接...
  • 定时器中断 外部中断 串口中断 基本概念 对于单片机来讲, 中断是指 CPU 在处理某一事件 A 时, 发生了另一事件 B, 请求 CPU 迅速去处理(中断发生); CPU 暂时停止当前的工作(中断响应), 转去 处理事件 B(中断...
  • LPC2124单片机的基础操作——GPIO、外部中断、定时器和串口LPC2124的简介LPC2124之GPIOGPIO简介编程习惯功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成...
  • 本篇博客讲解了外部中断,中断概念,阻塞式串口收发,串口通信概念,中断式串口收发,DMA串口收发,DMA空闲中断。内容比较多,而且很重要。
  • 满足CPU(可能)执行中断中断响应)的条件 中断源有中断请求 此中断源的中断允许位为1 CPU开总中断(EA=1) 常用的中断号与中断源等信息 2.上面显示的中断号与中断程序的关键字有关,interrupt X using N ,X为中断...
  • CAN总线具有6个特点:1:多主控制(挂接在总线上的所有设备均可以成为主设备,并且设备ID是用来决定设备的优先级,没有设备地址概念),2:系统若软性(没有设备地址概念),3、通讯速度较快,通讯距离较远(1Mbps下...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,851
精华内容 4,340
关键字:

串口中断概念