精华内容
下载资源
问答
  • 51单片机串口中断

    2014-07-11 09:31:55
    51单片机串口中断
  • 51单片机 串口中断

    千次阅读 2019-06-25 15:18:52
    1.什么是中断 广义上的中断是指一个过程,举个简单的例子,打开了电脑,你正在放音乐,点击了暂停按钮,于是歌停了。这就是一个很明显的中断的例子。CPU正在做自己的事情(放音乐),鼠标点击了暂停,就等于给了CPU...

    1.什么是中断

    广义上的中断是指一个过程,举个简单的例子,打开了电脑,你正在放音乐,点击了暂停按钮,于是歌停了。这就是一个很明显的中断的例子。CPU正在做自己的事情(放音乐),鼠标点击了暂停,就等于给了CPU一个中断信号,CPU收到中断信号之后,进入中断服务函数(里面写着停止播放音乐具体实现)。中断过程可以概述为:CPU正在做的事-->中断源触发中断-->CPU收到中断信号-->CPU处理中断--->CPU继续之前做的事

            在应用层方面,也就是我们把串口中断用起来目前只需掌握以下几点:

            ①中断源:就是中断的来源,如定时中断,串口中断(包括发送完成,接受完成等),DMA中断,按键中断,IO口输入高低电平等等都可以当做中断的来源。

            ②中断服务函数:就是有一个中断来了,这个中断具体要做什么。比如串口收到1帧数据,需要用变量把数据存起来,或者用来显示到屏幕上等等。

    2. 51单片机串口中断的实现

    单片机的串口中断实现分为两步:

      step1:初始化串口,单片机所有的外设(串口,定时器,CAN等等)本质上为配置寄存器的值来实现不同模式的选择,这一步其实是比较重复的工作,初学者有时间可以扣扣细节,没时间的话,就把它想成一个黑盒,配置几个变量即可使用。这里不细讲了,有空可以参考以下初始化的例程来理解,没空就只需要 修改Baudrate变量来使用自己想要的波特率。

    #define MAIN_Fosc		24000000L	//define main clock 即主频
    #define Baudrate		500000L		//define the baudrate
    						//12T mode: 600~115200 for 22.1184MHZ, 300~57600 for 11.0592MHZ
    						//1T  mode: 7200~1382400 for 22.1184MHZ, 3600~691200 for 11.0592MHZ
    #define BRT_Reload		(256 - MAIN_Fosc / 16 / Baudrate)	//Calculate the timer1 reload value ar 1T mode
    
    void uart_init(void)
    {
    	PCON |= 0x80;		//UART0 Double Rate Enable
    	SCON = 0x50;		//UART0 set as 10bit , UART0 RX enable
    
    	AUXR |=  0x01;		//UART0 使用BRT
    	AUXR |=  0x04;		//BRT set as 1T mode
    	BRT = BRT_Reload;
    	AUXR |=  0x10;		//start BRT	
    
    	ES  = 1;
    	EA = 1;
    }

    step2:串口中断服务子函数

    当初始化完成之后,程序则进入while(1),然后,当串口中断来了,则进入中断服务子函数,执行完之后再返回while(1)继续执行之前做的事情。常用的串口中断有发送完成中断(TI)和接收完成中断(RI),当发送完成变量TI置1,当接收完成RI置1。需要手动给变量赋值为0来接收下一次的中断。

    具体实现代码如下:

    //中断服务函数可以随便写  但interrupt 4代表的串口0中断
    //这是程序的框架
    void uart0_interrupt (void) interrupt 4
    {
    	if(RI)  //RI为1代表接收完成一帧数据
    	{
            /*
            需要具体做的事情
            */
    		RI = 0;//清除标志位,以便当接收到下一帧数据进入中断
    	}
    	if(TI)//TI为1代表发送完成中断
    	{
            /*
            需要具体做的事情
           */
    		TI = 0;//清除标志位,以便当接收到下一帧数据进入中断
    
    	}
    }

     

     

    展开全文
  • 51单片机 串口 中断

    2014-12-29 09:31:33
    想请问大神 51单片机串口在什么情况下会进入串口中断服务函数? 是在TI=1的时候?还是在RI=1的时候?还是2中情况下都会响应中断? 小弟不是很清楚,请大神指点,谢谢了先
  • 51单片机串口中断实验 串口向外部发送“齐鲁工业大学”六个字,一个汉字占用两个字节,六个字占用12个字节。 #include <reg51.h> unsigned char s[] = "齐鲁工业大学"; // 延时函数 void ...

    51单片机串口中断实验


     串口向外部发送“齐鲁工业大学”六个字,一个汉字占用两个字节,六个字占用12个字节。

     #include <reg51.h>
    
     unsigned char s[] = "齐鲁工业大学";
    
    
    // 延时函数
    void Delay10ms(unsigned int c)
    {
       unsigned char a, b;
    
        //--c已经在传递过来的时候已经赋值了,所以在for语句第一句就不用赋值了--//
        for (;c>0;c--)
        {
            for (b=38;b>0;b--)
            {
                for (a=130;a>0;a--);
            }          
        }       
    }
    
    
    // 初始化串口中断
    void UsartInit()
    {
        EA=0; //总中断关闭
        SCON = 0x50; // 控制寄存器
        PCON = 0x80;  // 记住就行,0x80
        TMOD = 0x20; // TMOD设置定时计数器的工作方式和功能 ,采用定时器1,工作方式2
        TH1 = 0xF3;     // 设置高八位
        TL1 = 0xF3;     // 设置低八位
        TR1=1;    // 使定时器1开始工作
        ES=1;  // 开启串口中断
        EA=1;  // 开启总中断权限
    }
    
    // 主函数
    void main()
    {
        // 初始化
        UsartInit();
        while(1)
        {      unsigned int i;
            // 发送数组数据
            for(i=0;i<12;i++)
            {
                // 将SBUF中的数据发送出去
                SBUF = s[i];
                // 如果发送完成,TI自动置1
                while(!TI);
                // 发送完成,软件置0
                TI=0;
            }
            //延时
            Delay10ms(10);
        }
    }

      

     


     

     优化之前代码,封装发送方法。

    #include <reg51.h>
    #include <stdio.h>
    
    unsigned char s[] = "齐鲁工业大学";
    
    
    // 延时函数
    void Delay10ms(unsigned int c)
    {
       unsigned char a, b;
    
        //--c已经在传递过来的时候已经赋值了,所以在for语句第一句就不用赋值了--//
        for (;c>0;c--)
        {
            for (b=38;b>0;b--)
            {
                for (a=130;a>0;a--);
            }          
        }       
    }
    
    
    // 初始化串口中断
    void UartInit()
    {
        EA=0; //总中断关闭
        SCON = 0x50; // 控制寄存器
        PCON = 0x80;  // 记住就行,0x80
        TMOD = 0x20; // TMOD设置定时计数器的工作方式和功能 ,采用定时器1,工作方式2
        TH1 = 0xF3;     // 设置高八位
        TL1 = 0xF3;     // 设置低八位
        TR1=1;    // 使定时器1开始工作
        ES=1;  // 开启串口中断
        EA=1;  // 开启总中断权限
    }
    
    // 封装发送方法
    void UartSend(char *Data,char len)
    {
        unsigned int i;
        // 发送数组数据
        for(i=0;i<len;i++)
        {
            // 将SBUF中的数据发送出去
            SBUF = *Data++;
            // 如果发送完成,TI自动置1
            while(!TI);
            // 发送完成,软件置0
            TI=0;
        }
        //延时
        Delay10ms(10);
    }
    
    // 主函数
    void main()
    {
        // 初始化
        UartInit();
        while(1)
        {      
            // 调用封装的发送函数
            UartSend(s,12);
        }
    }

     


     串口接收消息,然后将消息从串口发送出去

    #include <reg51.h>
    #include <stdio.h>
    
    unsigned char s[] = "齐鲁工业大学";
    
    
    // 延时函数
    void Delay10ms(unsigned int c)
    {
       unsigned char a, b;
    
        //--c已经在传递过来的时候已经赋值了,所以在for语句第一句就不用赋值了--//
        for (;c>0;c--)
        {
            for (b=38;b>0;b--)
            {
                for (a=130;a>0;a--);
            }          
        }       
    }
    
    
    // 初始化串口中断
    void UartInit()
    {
        EA=0; //总中断关闭
        SCON = 0x50; // 控制寄存器
        PCON = 0x80;  // 记住就行,0x80
        TMOD = 0x20; // TMOD设置定时计数器的工作方式和功能 ,采用定时器1,工作方式2
        TH1 = 0xF3;     // 设置高八位
        TL1 = 0xF3;     // 设置低八位
        TR1=1;    // 使定时器1开始工作
        ES=1;  // 开启串口中断
        EA=1;  // 开启总中断权限
    }
    
    // 封装发送方法
    void UartSend(char *Data,char len)
    {
        unsigned int i;
        // 发送数组数据
        for(i=0;i<len;i++)
        {
            // 将SBUF中的数据发送出去
            SBUF = *Data++;
            // 如果发送完成,TI自动置1
            while(!TI);
            // 发送完成,软件置0
            TI=0;
        }
        //延时
        Delay10ms(10);
    }
    
    
    // 接收,串口中断
    void Uart() interrupt 4
    {
        unsigned char rev;
        rev = SBUF;
        RI=0; // 接收中断标志位置0;
        SBUF = rev;
        while(!TI);
        TI = 0;       // 发送中断标志位置0;
    }
    
    // 主函数
    void main()
    {
        // 初始化
        UartInit();
        while(1)
        {      
            // 调用封装的发送函数
            // UartSend(s,12);
        }
    }

     

     


     

    实验相关寄存器


     

    转载于:https://www.cnblogs.com/wjw1014/p/10115052.html

    展开全文
  • 关于51单片机串口中断的理解 关于这个问题找了好几个帖子,都没看到能让我明白的。自己就想了想,又看了看。新手不一定说得对,您凑合着看看。要不对的话,望指正。 首先,我们在SCON中设置的时候,一般都会将接收使...

    关于51单片机串口中断的理解

    关于这个问题找了好几个帖子,都没看到能让我明白的。自己就想了想,又看了看。新手不一定说得对,您凑合着看看。要不对的话,望指正。
    首先,我们在SCON中设置的时候,一般都会将接收使能位REN置1。
    其次,串口的收发都会用到SBUF寄存器。
    当我们在接收数据时,因为接收使能位已经置1,所以数据就依次存入SBUF。数据存入完毕RI自动置1,从而触发中断。
    当我们发送数据时,数据存入SBUF后,数据就会自动发送,当发送完毕,TI位置1,从而也可以进入串口中断。
    这是个人理解哈,因为是自学,所以也不知道对不对。
    
    展开全文
  • 51单片机通过串口与PC机通信,采用中断的方式
  • 51单片机串口功能就是和外界进行通讯,所谓的“外界”也就是与单片机进行交互的媒介,最常用的就是我们经常使用的计算机、平板或者其他设备(比如另一个单片机配合显示模块使用)。 既然和外界需要“交互”,就...

    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三个位的设置可以指定波特率发生器的时钟基准

    SM0 SM1 模式 描述 波特率时钟基准
    0 0 0 半双工状态,发送接收8位数据,使用移位寄存器 f_osc/12
    0 1 1 全双工状态,发送10位数据 定时器1的溢出率/PCON寄存器SMOD位
    1 0 2 全双工状态,发送11位数据 f_osc/16或者f_osc/32
    1 1 3 全双工状态,发送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后等待下一次发送、接收数据)

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

     

     

    展开全文
  • 如果不使用中断,是不是直接查询接收和发送就行?
  • [b]玩单片机有大约半年的时间了,今玩玩串口中断,搞不清它的工作过程(也就是不熟悉它的工作原理) 我想问的是 1 我先把数据装在串行发送寄存器(与串行接收寄存器共用一个物理地址),然后将数据发送出去,是在...
  • 2.参照下面这一篇博客,为什么单片机串口设置9600波特率的时候总是接收不到正确数据? 因为12Mhz的单片机9600波特通信设置T1初值为FD时有8.51%的误差,而允许误差为4.5%以下!! 解决方法:用4800波特率,...
  • 串口中断函数: void ser_int (void) interrupt 4 using 1 { LED_CHECK=1; //用acq启动后,主函数运行到底部也未把此处LED灯灭掉,说明未卡在中断函数中 if(RI == 1) //RI接受中断标志 { RI = 0; //...
  • 51单片机串口通讯中断应用
  • 51单片机串口通讯中断应用keil工程文件C源文件,链接好串口,波特率设置为9600,无奇偶校验,文件注释非常详细
  • 本文主要介绍了51单片机是如何产生中断的。
  • 本文主要讲了关于51单片机串口通信需要加超时中断这个问题,下面来看一下
  • 51单片机采用中断方式的串口通信过程及程序分析:所谓中断方式,就是串口收/发标志位出发中断后,在中断中执行既定操作,可通过函数调用来实现。接收数据时: 等待中断->然后在中断中接收数据发送数据时: 发送数据...
  • 单片机C51串口中断.pdf

    2008-05-31 18:18:49
    单片机C51串口中断.pdf 单片机 C51 串口中断 嵌入式编程 <br>经典学习书籍
  • 这是一个单片机C51串口接收(中断)和发送例程,可以用来测试51单片机中断接收 ,和查询发送,另外我觉得发送没有必要用中断,因为程序的开销是一样的 。
  • 本文主要讲了51单片机串口通信是否需要加超时中断这个问题,下面一起来学习一下
  • 中断来实现串口通信//这是一个单片机C51串口接收(中断)和发送例程,可以用来测试51单片机中断接收 //和查询发送,另外我觉得发送没有必要用中断,因为程序的开销是一样
  • 51单片机 串口通信 中断

    千次阅读 2011-03-01 16:01:00
    实现电脑向单片机发送一些数据,单片机返回相同的数据 #include #define uchar unsigned char #define uint unsigned int unsigned char flag,a,i;//声明标志位 flag uchar code table[]="I get" void init...
  • 51单片机串口接收

    2017-10-20 10:37:05
    51单片机串口接收中断,发送中断源代码。定时器1作为波特率发生器,晶振11.0592MHz
  • 51单片机串口通讯-中断版例程.在AT89S52上测试过,收发完全正常,使用11.0592晶体.串口使用标标准设置:9600,n,8,1,使用串口通讯调试器XP.
  • 最近项目里面要用到51单片机做一些控制,主要功能是通过串口接收上位机的指令并进行分析解码,等待一个外部触发信号到来后执行之前接收的指令动作。正好手边有一片STC89C52,赶紧搭了个最小系统。STC89C52单片机可以...
  • 学习51单片机必备--串口中断 学习51单片机必备--串口中断
  • 串行发送中断标志TI和接收中断标志RI是同一个中断源,CPU事先不知道是发送中断TI还是接收中断RI产生的中断请求,所以,在全双工通信时,必须由软件来判别。复位时SCON所有位都清0.2)PCON电源控制位寄存器PCON中只有...
  • 51单片机串口通信代码作者:佚名来源:本站原创点击数:9407更新时间:2007年06月17日【字体:大中小】1....程序如下://这是一个单片机C51串口接收(中断)和发送例程,可以用来测试51单片机中断接收//和查询发送...
  • 51单片机默认使用定时器1作为串口通信的波特率发生器、定时器1中断通信,串口与定时器1冲突,在遇到定时器不够用的时候可以用定时器2
  • 51单片机串口通信 采用中断方式

    万次阅读 2018-01-07 22:31:01
    功能: 连接串口到电脑,下载该程序,打开电源 打开串口调试助手,将波特率设置为2400,无奇偶校验 晶振12MHz,发送和接收使用的格式相同,如都使用 字符型格式,设置正确后接受框可以显示出: The UART test,...
  • 8-bitreload*/TH1=0xFD;/*TH1:reloadvaluefor9600baud@11.0592MHz*/TR1=1;/*TR1:timer1run*/EA=1;.../*打开串口中断*/while(1)/*主循环不做任何动作*/{}}voidUART_SER(void)interrupt4//串行中断...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 754
精华内容 301
关键字:

51单片机串口中断