精华内容
下载资源
问答
  • 51单片机——串口通信

    千次阅读 2021-06-17 23:28:18
    51单片机——串口通信串口通信?串口通信的原理?串口的配置定时器的配置c源代码netty源代码结果 本篇博客的最终效果是实现51单片机用串口发送Hello World,netty监听串口读到Hello World后回发给51单片机,最终51...


    本篇博客的最终效果是实现51单片机用串口发送Hello World,netty监听串口读到Hello World后回发给51单片机,最终51单片机回显到LCD1602显示屏。

    串口通信?

    其实我压根不知道串口通信是啥,我在这方面也是小白,只知道按照标准做就可以实现通信。
    在这里插入图片描述
    上图示是四孔串口,应该算是全双工通信的,复杂的有9针串口,提供额外的口子可以调控发送速率等。

    在这里插入图片描述

    开发板原理图如下:
    在这里插入图片描述

    串口通信的原理?

    我们知道串口通信是要设置一个波特率的,比如4800bit/s, 那么这个数据发送速率如何控制呢?
    定时器那篇博客里说了12MHz的晶振,一个指令周期是1us,每过一个1us,定时器+1,加到溢出了,发出一个溢出中断,然后就去发送码元数据,这样去控制码元的发送速率。

    定时器初值的计算
    关于串口定时器初值计算,我没搞懂,但是他有公式,套用公式即可
    公式:TL1 = 256 - fosc * (SMOD + 1) / (384 * 波特率)
    我的单片机是11.0592MHz,fosc=11.0592*1000000, 晶振每s振动次数
    TL1= 256 - 11059200/384/4800 = 250 = 0xFA

    这里用的定时器是定时器1,8位重装,8位最大255,加到溢出值256,初始值和重装值都设置为0xFA
    TL1 = 0xFA; //设定定时初值
    TH1 = 0xFA; //设定定时器重装值

    软件计算
    感觉之所以出11.0592MHz的原因可能就是用这个计算误差为0,如果是12MHz的不管怎么计算都会有误差,但是12MHz的采用12分频的话一个指令周期正好1us。
    在这里插入图片描述

    串口的配置

    在这里插入图片描述SCON配置
    在这里插入图片描述REN::接收使能,为0代表51单片机的串口不接受数据,我们需要接收置位为1
    TB8,RB8:不用管,只有在方式2和方式3 9位UART下才用得到
    TI:发送数据中断标志位,在发完8位数据后,由内部硬件自动置位为1,我们需要软件复位为0
    RI:接收数据中断标志位,在接完8位数据后,由内部硬件自动置位为1,我们需要软件复位为0
    SCON=0x50

    SBUF是一字节缓冲区,发送的时候直接SBUF='A’就把A发送到串口了,接收的时候char a = SBUF就可以了

    PCON配置
    在这里插入图片描述
    B7的SMOD=1开启倍速,我们不需要倍速,8为全0就好。
    PCON=0; 为了不影响其他位一般这样写PCON &= 0x7F;

    IE配置
    这里配的是UART中断的配置‘
    在这里插入图片描述EA=1,ES=1允许UART中断,netty从串口发来的数据,是要经过这个中断处理程序的:void UART_Routine() interrupt 4

    串口模式图:
    在这里插入图片描述
    在这里插入图片描述

    定时器的配置

    之前有详细说过定时器0的配置,这里就不说了,具体查看STC89C52文档第7章

    	//定时器配置
    	TMOD &= 0x0F;		//清除定时器1模式位
    	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
    	//上面两行等价TMOD=0x20
    	TL1 = 0xFA;		//设定定时初值
    	TH1 = 0xFA;		//设定定时器重装值
    	ET1 = 0;		//禁止定时器1中断,这里不需要定时器的中断,只需要计时
    	TR1 = 1;		//启动定时器1
    

    c源代码

    Delay.c

    
    void Delay(unsigned int xms)
    {
    	unsigned char i, j;
    	while(xms--)
    	{
    		i = 2;
    		j = 239;
    		do
    		{
    			while (--j);
    		} while (--i);
    	}
    }
    
    
    

    Delay.h

    #ifndef __DELAY_H__
    #define __DELAY_H__
    
    void Delay(unsigned int xms);
    
    #endif
    
    

    LCD1602.c

    #include <REGX52.H>
    #include <Delay.h>
    //引脚配置:
    sbit LCD_RS=P2^6;
    sbit LCD_RW=P2^5;
    sbit LCD_EN=P2^7;
    #define LCD_DataPort P0
    
    
    /**
      * @brief  LCD1602写命令
      * @param  Command 要写入的命令
      * @retval 无
      */
    void LCD_WriteCommand(unsigned char Command)
    {
    	LCD_RS=0;
    	LCD_RW=0;
    	LCD_DataPort=Command;
    	LCD_EN=1;
    	Delay(1);
    	LCD_EN=0;
    	Delay(1);
    }
    
    /**
      * @brief  LCD1602写数据
      * @param  Data 要写入的数据
      * @retval 无
      */
    void LCD_WriteData(unsigned char Data)
    {
    	LCD_RS=1;
    	LCD_RW=0;
    	LCD_DataPort=Data;
    	LCD_EN=1;
    	Delay(1);
    	LCD_EN=0;
    	Delay(1);
    }
    
    /**
      * @brief  LCD1602设置光标位置
      * @param  Line 行位置,范围:1~2
      * @param  Column 列位置,范围:1~16
      * @retval 无
      */
    void LCD_SetCursor(unsigned char Line,unsigned char Column)
    {
    	if(Line==1)
    	{
    		LCD_WriteCommand(0x80|(Column-1));
    	}
    	else if(Line==2)
    	{
    		LCD_WriteCommand(0x80|(Column-1+0x40));
    	}
    }
    
    /**
      * @brief  LCD1602初始化函数
      * @param  无
      * @retval 无
      */
    void LCD_Init()
    {
    	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
    	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
    	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
    	LCD_WriteCommand(0x01);//光标复位,清屏
    }
    
    /**
      * @brief  在LCD1602指定位置上显示一个字符
      * @param  Line 行位置,范围:1~2
      * @param  Column 列位置,范围:1~16
      * @param  Char 要显示的字符
      * @retval 无
      */
    void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
    {
    	LCD_SetCursor(Line,Column);
    	LCD_WriteData(Char);
    }
    
    /**
      * @brief  在LCD1602指定位置开始显示所给字符串
      * @param  Line 起始行位置,范围:1~2
      * @param  Column 起始列位置,范围:1~16
      * @param  String 要显示的字符串
      * @retval 无
      */
    void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
    {
    	unsigned char i;
    	LCD_SetCursor(Line,Column);
    	for(i=0;String[i]!='\0';i++)
    	{
    		LCD_WriteData(String[i]);
    	}
    }
    
    /**
      * @brief  返回值=X的Y次方
      */
    int LCD_Pow(int X,int Y)
    {
    	unsigned char i;
    	int Result=1;
    	for(i=0;i<Y;i++)
    	{
    		Result*=X;
    	}
    	return Result;
    }
    
    /**
      * @brief  在LCD1602指定位置开始显示所给数字
      * @param  Line 起始行位置,范围:1~2
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:0~65535
      * @param  Length 要显示数字的长度,范围:1~5
      * @retval 无
      */
    void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
    {
    	unsigned char i;
    	LCD_SetCursor(Line,Column);
    	for(i=Length;i>0;i--)
    	{
    		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
    	}
    }
    
    /**
      * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
      * @param  Line 起始行位置,范围:1~2
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:-32768~32767
      * @param  Length 要显示数字的长度,范围:1~5
      * @retval 无
      */
    void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
    {
    	unsigned char i;
    	unsigned int Number1;
    	LCD_SetCursor(Line,Column);
    	if(Number>=0)
    	{
    		LCD_WriteData('+');
    		Number1=Number;
    	}
    	else
    	{
    		LCD_WriteData('-');
    		Number1=-Number;
    	}
    	for(i=Length;i>0;i--)
    	{
    		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
    	}
    }
    
    /**
      * @brief  在LCD1602指定位置开始以十六进制显示所给数字
      * @param  Line 起始行位置,范围:1~2
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:0~0xFFFF
      * @param  Length 要显示数字的长度,范围:1~4
      * @retval 无
      */
    void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
    {
    	unsigned char i,SingleNumber;
    	LCD_SetCursor(Line,Column);
    	for(i=Length;i>0;i--)
    	{
    		SingleNumber=Number/LCD_Pow(16,i-1)%16;
    		if(SingleNumber<10)
    		{
    			LCD_WriteData(SingleNumber+'0');
    		}
    		else
    		{
    			LCD_WriteData(SingleNumber-10+'A');
    		}
    	}
    }
    
    /**
      * @brief  在LCD1602指定位置开始以二进制显示所给数字
      * @param  Line 起始行位置,范围:1~2
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
      * @param  Length 要显示数字的长度,范围:1~16
      * @retval 无
      */
    void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
    {
    	unsigned char i;
    	LCD_SetCursor(Line,Column);
    	for(i=Length;i>0;i--)
    	{
    		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
    	}
    }
    
    

    LCD1602.h

    #ifndef __LCD1602_H__
    #define __LCD1602_H__
    
    //用户调用函数:
    void LCD_Init();
    void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
    void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
    void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
    void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
    void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
    void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
    
    #endif
    
    

    UART.h

    #ifndef __UART_H__
    #define __UART_H__
    
    void UART_Init();
    void UART_SendByte(unsigned char Byte);
    
    #endif
    
    

    UART.c

    #include <REGX52.H>
    
    
    //11.0592MHz
    //fosc=11.0592*1000000, 晶振每s振动次数
    // TL1 = 256 - fosc * (SMOD + 1) / (384 * 波特率)
    // TL1= 256 - 11059200/384/4800 = 250 = 0xfa
    void UART_Init()
    {
    	//PCON |= 0x80; //波特率倍速 smod=1,9600
    	//TL1 = 0xF4;		//设定定时初值
    	//TH1 = 0xF4;		//设定定时器重装值
    	PCON=0;
    	//PCON &= 0x7F;		//波特率不倍速 smod=0,4800
    	SCON = 0x50;		//8位数据,可变波特率
    	
    	//定时器配置
    	TMOD &= 0x0F;		//清除定时器1模式位
    	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
    	TL1 = 0xFA;		//设定定时初值
    	TH1 = 0xFA;		//设定定时器重装值
    	ET1 = 0;		//禁止定时器1中断
    	TR1 = 1;		//启动定时器1
    	
    	//串口中断配置
    	EA=1;
    	ES=1;
    }
    /**
      * @brief  串口发送一个字节数据
      * @param  Byte 要发送的一个字节数据
      * @retval 无
      */
    void UART_SendByte(unsigned char Byte)
    {
    	SBUF=Byte;
    	while(TI==0);
    	//到这里说明TI=1,因为硬件置为1
    	//手工复位
    	TI=0;
    }
    
    

    main.c

    #include <REGX52.H>
    #include "Delay.h"
    #include "UART.h"
    #include "LCD1602.h"
    void main()
    {
    	unsigned char cs[] = {0x10,11,'H','e','l','l','o',' ','W','o','r','l','d',0x16};
    	char i = 0;
    	LCD_Init();
    	
    	UART_Init();			//串口初始化
    	
    	Delay(3000);		//延时
    	
    	
    	while(i<14){
    		UART_SendByte(cs[i]);	//串口发送一个字节
    		Delay(10);		//延时
    		i++;
    	}
    			
    	while(1){}
    	
    }
    
    //下面这个中断程序是接收netty的返回数据
    char col = 0;
    unsigned char rcs[14];
    char i = 0;
    void UART_Routine() interrupt 4
    {
    	if(RI==1)					//如果接收标志位为1,接收到了数据
    	{
    		rcs[col++] = SBUF;
    		if(col==14){
    			LCD_ShowString(1,0,rcs);
    		}
    		RI=0;					//接收标志位清0
    	}
    }
    

    netty源代码

    netty代码有点多,我就说个大概,可以去git拉。

    整体流程如下:
    在这里插入图片描述
    协议如下图
    在这里插入图片描述单片机发送的数据如下:
    unsigned char cs[] = {0x10,11,‘H’,‘e’,‘l’,‘l’,‘o’,’ ',‘W’,‘o’,‘r’,‘l’,‘d’,0x16};

    第一步经过FrameDecoder
    在这里插入图片描述
    第二步经过PacketDecoder
    在这里插入图片描述第三步经过PacketHandler
    在这里插入图片描述

    git码云代码,代码在com.lry.netty01.rx,其他代码不用管,另外java串口通信需要一些jar包,放到jdk里面,具体的自己搜搜看

    结果

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

    展开全文
  • STC系列芯片的串口通信编程

    千次阅读 2020-07-10 18:15:54
    开发板上有关串口通讯的有:TMOD(定时器寄存器)、CSON(串口通信寄存器)、PCON(开发板电源控制寄存器)以及与51系列单片机区别最大的AUXR(分频寄存器)四种,其中以SCON最重要,其他的只是稍微设置下即可,串口...

    STC系列芯片的串口通信编程

    本人使用的是基于STC15F2K60S2芯片的开发板。

    开发板上有关串口通讯的有:TMOD(定时器寄存器)、CSON(串口通信寄存器)、PCON(开发板电源控制寄存器)以及与51系列单片机区别最大的AUXR(分频寄存器)四种,其中以SCON最重要,其他的只是稍微设置下即可,串口通信初始化乍看很难,但沉下心来仔细研究,相信什么都难不倒我们。

    1、TMOD(定时器寄存器)
    有单片机基础的想必都知道应该怎么设置,这里我设置的是定时器1,自动重载模式

    	TMOD=0x20;  //定时器1工作方式2(自动重载)
    	TH1=0XFD;
    	TL1=0XFD;  //设置初始值,该初值在晶振频率为11.0592Hz的前提下波特率为9600
        //PCON=0X80;   //波特率加倍,加倍为9600    可选用
    

    波特率的计算比较繁琐,我们这里直接使用了最常用的波特率设置

    2、SCON(串口通信寄存器)
    串口通信最重要的寄存器,可位寻址
    CSON
    关于SM0,SM1:我们在这里只需要了解SM0,SM1是设置串口的工作模式的,这个大部分情况我们选择模式2,即SM0=0,SM1=1;

    关于REN:串口是否允许中断,这里我们选择允许,即REN=1;

    关于TI,RI,主要是在程序内部使用,作为串口读写数据完毕的标志,串口读写完毕后会由硬件将他们置1,编程中需我们手动清零
    在这里插入图片描述
    在这里插入图片描述

    	SM0=0;
    	SM1=1;    //串口通信选择方式2
    	REN=1;   //开启串口通信
    	//SCON=0x50;     两者等价
    

    3、PCON(开发板电源控制寄存器)
    PCON第7位控制波特率是否倍频,即PCON=0x80,波特率加倍,PCON=0x00或者不设置,波特率不加倍

    4、AUXR(分频寄存器)
    最后一个,也是STC芯片和51芯片在串口通信上不同的地方
    在这里插入图片描述常用的就最后两位,选择定时器0或者定时器1是否12分频
    我们这里选择定时器1为1T,所以设置AUXR=0x40;
    Ps:一定注意,STC系列的芯片一定要设置AUXR,AUXR=0x40;也好,AUXR=0x00;也好,一定要设置!!!不然串口通信无法实现,本人亲测

    最后,贴出我的代码,希望对需要的人有所帮助

    /*************************************************************************
    *测试程序:
    *程序功能:上位机每发送一个字节开发板的全部led灯都切换一次状态
    *开发板led初始状态为熄灭
    
    *标签:串口读取程序 循环查询
    *************************************************************************/
    
    #include "STC15F2K60S2.H"
    
    #define Y4 P2=((P2&0x1f)|0x80)
    #define Y5 P2=((P2&0x1f)|0xa0)
    #define Y6 P2=((P2&0x1f)|0xc0)
    #define Y7 P2=((P2&0x1f)|0xe0)
    
    void uart_init()
    {
    //	SM0=0;
    //	SM1=1;    //串口通信选择方式2
    //	REN=1;   //开启串口通信
    	SCON=0X50;
    	
    	TMOD=0x20;  //定时器1工作方式2(自动重载)
    	TH1=0XFD;
    	TL1=0XFD;  //设置初始值,该初值在晶振频率为11.0592Hz的前提下波特率为9600
    	
    	TR1=1;  //开启定时器1
    	EA=1;  //CPU允许中断
      ES=1; //允许串口中断
      PCON=0X80;   //波特率加倍,为9600
    	AUXR = 0x00;
    }
    
    
    
    int i=1;
    
    void main()
    {
    	Y4;P0=0xff;
    	Y5;P0=0x00;
    	uart_init();
    	while(1)
    	{
    		while(!RI);  //当接收到 字节接收完成 的标志时
    		if(i%2==1){Y4;P0=0x00;}
    		else {Y4;P0=0xff;}
    		i++;
    		RI=0;   //软件复位
    	}
    }
    
    ``
    
    
    展开全文
  • 7.STC15W408AS单片机串口通信

    千次阅读 2021-07-20 14:13:36
    STC15W408AS只有一个串口串口1,有4种工作方式,其中两种方式的波特率是可变的,另两种是固定的,以供不同应用场合选用。 一、串口1相关寄存器 下面只把接下来我需要的寄存器和寄存器的位说明一下。 1.1 控制...

            STC15W408AS只有一个串口,串口1,有4种工作方式,其中两种方式的波特率是可变的,另两种是固定的,以供不同应用场合选用。

    一、串口1相关寄存器

    下面只把接下来我需要的寄存器和寄存器的位说明一下。

    1.1 控制寄存器SCON

    其中SM0、SM1按下列组合确定串行口1的工作方式:

    REN:允许/禁止串行接收控制位。由软件置位REN,即REN=1为允许串行接收状态,可启动串行接收器RxD,开始接收信息。软件复位REN,即REN=0,则禁止接收。

    TI: 发送中断请求标志位。在方式0,当串行发送数据第8位结束时,由内部硬件自动置位,即TI=1,向主机请求中断,响应中断后TI必须用软件清零,即TI=0。在其他方式中,则在停止位开始发送时由内部硬件置位,即TI=1,响应中断后TI必须用软件清零。

    RI: 接收中断请求标志位。在方式0,当串行接收到第8位结束时由内部硬件自动置位RI=1,向主机请求中断,响应中断后RI必须用软件清零,即RI=0。在其他方式中,串行接收到停止位的中间时刻由内部硬件置位,即RI=1,向CPU发中断申请,响应中断后RI必须由软件清零。串行通信的中断请求:当一帧发送完成,内部硬件自动置位TI,即TI=1,请求中断处理;当接收完一帧信息时,内部硬件自动置位RI,即RI=1,请求中断处理。由于TI和RI以"或逻辑"关系向主机请求中断,所以主机响应中断时事先并不知道是TI还是RI请求的中断,必须在中断服务程序中查询TI和RI进行判别,然后分别处理。因此,两个中断请求标志位均不能由硬件自动置位,必须通过软件清0,否则将出现一次请求多次响应的错误。电源控制寄存器PCON中的SMOD/PCON.7用于设置方式1、方式2、方式3的波特率是否加倍。

    1.2 数据缓冲寄存器SBUF

            STC15系列单片机的串行口1缓冲寄存器(SBUF)的地址是99H,实际是2个缓冲器,写SBUF的操作完成待发送数据的加载,读SBUF的操作可获得已接收到的数据。两个操作分别对应两个不同的寄存器,1个是只写寄存器,1个是只读寄存器。串行通道内设有数据寄存器。在所有的串行通信方式中,在写入SBUF信号(MOV SBUF,A)的控制下,把数据装入相同的9位移位寄存器,前面8位为数据字节,其最低位为移位寄存器的输出位。根据不同的工作方式会自动将 1" TB8的值装入移位寄存器的第9位,并进行发送。串行通道的接收寄存器是一个输入移位寄存器。在方式0时它的字长为8位,其他方式时为9位。当一帧接收完毕,移位寄存器中的数据字节装入串行数据缓冲器SBUF中,其第9位则装入SCON寄存器中的RB8位。如果由于SM2使得已接收到的数据无效时,RB8和SBUF中内容不变。由于接收通道内设有输入移位寄存器和SBUF缓冲器,从而能使一帧接收完将数据由移位寄存器装入SBUF后,可立即开始接收下一帧信息,主机应在该帧接收结束前从SBUF缓冲器中将数据取走,否则前一帧数据将丢失。SBUF以并行方式送往内部数据总线。

    1.3 辅助寄存器AUXR

    T0x12: 定时器0速度控制位

            0, 定时器0是传统8051速度,12分频;

            1, 定时器0的速度是传统8051的12倍,不分频

    T1x12: 定时器1速度控制位

            0, 定时器1是传统8051速度,12分频;

            1, 定时器1的速度是传统8051的12倍,不分频

    如果UART1/串口1用T1作为波特率发生器,则由T1x12决定UART1/串口是12T还是1T

    UART_M0x6: 串口模式0的通信速度设置位

            0, 串口1模式0的速度是传统8051单片机串口的速度,12分频;

            1, 串口1模式0的速度是传统8051单片机串口速度的6倍,2分频

    T2R: 定时器2允许控制位

            0, 不允许定时器2运行;

            1, 允许定时器2运行

    T2_C/T: 控制定时器2用作定时器或计数器

            0, 用作定时器(对内部系统时钟进行计数);

            1, 用作计数器(对引脚T2/P3.1的外部脉冲进行计数)

    T2x12: 定时器2速度控制位

            0, 定时器2是传统8051速度,12分频;

            1, 定时器2的速度是传统8051的12倍,不分频

    如果串口1或串口2用T2作为波特率发生器,则由T2x12决定串口1或串口2是12T还是1T.

    EXTRAM: 内部/外部RAM存取控制位

            0, 允许使用逻辑上在片外、物理上在片内的扩展RAM;

            1, 禁止使用逻辑上在片外、物理上在片内的扩展RAM

    S1ST2: 串口1(UART1)选择定时器2作波特率发生器的控制位

            0, 选择定时器1作为串口1(UART1)的波特率发生器;

            1, 选择定时器2作为串口1(UART1)的波特率发生器,此时定时器1得到释放,可以作为独立定时器使用串口1可以选择定时器1做波特率发生器,也可以选择定时器2作为 波特率发生器当设置AUXR寄存器中的S1ST2位(串行口波特率选择位)为1时,串行口1选择定时器2作为波特率发生器,此时定时器1可以释放出来作为定时器/计数器/时钟输出使用。

            对于STC15系列单片机,串口2只能使用定时器2作为其波特率发生器,不能够选择其他定时器作为波特率发生器。而串口1默认选择定时器2作为其波特率发生器,也可以选择定时器1作为其波特率发生器;串口3默认选择定时器2作为其波特率发生器,也可以选择定时器3作为其波特率发生器;串口4默认选择定时器2作为其波特率发生器,也可以选择定时器4作为其波特率发生器。

    1.4 定时器2的寄存器T2H, T2L

    定时器2寄存器T2H(地址为D6H,复位值为00H)及寄存器T2L(地址为D7H,复位值为00H)用于保存重装时间常数。

    注意:对于STC15串口2只能使用定时器2作为其波特率发生器,不能够选择其他定时器作为波特率发生器;而串口1默认选择定时器2作为其波特率发生器,也可以选择定时器1作为其波特率发生器;串口3默认选择定时器2作为其波特率发生器,也可以选择定时器3作为其波特率发生器;串口4默认选择定时器2作为其波特率发生器,也可以选择定时器4作为其波特率发生器。

    1.5 与串行口1中断相关的寄存器位ES和PS

    串行口中断允许位ES位于中断允许寄存器IE中,中断允许寄存器的格式如下:

    IE : 中断允许寄存器 (可位寻址)

    EA : CPU的总中断允许控制位

            EA=1,CPU开放中断,

            EA=0,CPU屏蔽所有的中断申请。

    EA的作用是使中断允许形成多级控制。即各中断源首先受EA控制;其次还受各中断源自己的

    中断允许控制位控制。

    ES : 串行口中断允许位

            ES=1,允许串行口中断,

            ES=0,禁止串行口中断。

    IP : 中断优先级控制寄存器低 (可位寻址)

    PS: 串行口1中断优先级控制位。

    当PS=0时,串行口1中断为最低优先级中断(优先级0)

    当PS=1时,串行口1中断为最高优先级中断(优先级1)

    二、串口1工作模式1:8位UART,波特率可变

            当软件设置SCON的SM0、SM1为"01" 时,串口1则以模式1工作。此模式为8位UART格式,一帧信息为10位:1位起始位,8位数据位(低位在先)和1位停止位。波特率可变,即可根据需要进行设置。TxD/P3.1为发送信息,RxD/P3.0为接收端接收信息,串行口为全双工接受/发送串行口模式1的发送过程:串行通信模式发送时,数据由串行发送端TxD输出。当主机执行一条写 SBUF" 的指令就启动串行通信的发送,写"SBUF"信号还把"1"装入发送移位寄存器的第9位,并通知TX控制单元开始发送。发送各位的定时是由16分频计数器同步。移位寄存器将数据不断右移送TxD端口发送,在数据的左边不断移入"0"作补充。当数据的最高位移到移位寄存器的输出位置,紧跟其后的是第9位 1" ,在它的左边各位全为"0" ,这个条件,使TX控制单元作最后一次移位输出,然后使允许发送信号 SEND"失效,完成一帧信息的发送,并置位中断请求位TI,即TI=1,向主机请求中断处理。

            模式1的接收过程:当软件置位接收允许标志位REN,即REN=1时,接收器便以选定波特率的16分频的速率采样串行接收端口RxD,当检测到RxD端口从 "1"→"0"的负跳变时就启动接收器准备接收数据,并立即复位16分频计数器,将1FFH植装入移位寄存器。复位16分频计数器是使它与输入位时间同步。16分频计数器的16个状态是将1波特率(每位接收时间)均为16等份,在每位时间的7、8、9状态由检测器对RxD端口进行采样,所接收的值是这次采样直经"三中取二" 即3次采样至少2次相同的值,以此消除干扰影响,提高可靠性。在起始位,如果接收到的值不为"0"(低电平),则起始位无效,复位接收电路,并重新检测 1"→0" 的起始位有效,则将它输入移位寄存器,并接收本帧的其余信息。接收的数据从接收移位寄存器的右边移入,已装入的1FFH向左边移出,当起始位 0" 移位寄存器的最左边时,使RX控制器作最后一次移位,完成一帧的接收。若同时满足以下两个条件:

    ·RI=0;

    ·SM2=0或接收到的停止位为1。

    则接收到的数据有效,实现装载入SBUF,停止位进入RB8,置位RI,即RI=1,向主机请求中断,若上述两条件不能同时满足,则接收到的数据作废并丢失,无论条件满足与否,接收器重又检测RxD端口上的 "1"→"0"的跳变,继续下一帧的接收。接收有效,在响应中断后,必须由软件清0,即RI=0。通常情况下,串行通信工作于模式1时,SM2设置为"0"。

    三、串口1测试程序

    #include "stc15.h"
    
    typedef unsigned char BYTE;
    typedef unsigned int WORD;
    
    #define FOSC 11059200L          //系统频率
    #define BAUD 9600               //串口波特率
    
    void SendData(BYTE dat);
    void SendString(char *s);
    
    void main()
    {
    	SCON = 0x50;                //8位可变波特率 串口工作模式1
    	T2L = (65536 - (FOSC/4/BAUD));   //设置波特率重装值
    	T2H = (65536 - (FOSC/4/BAUD))>>8;
    	AUXR = 0x14;                //T2为1T模式, 并启动定时器2
    	AUXR |= 0x01;               //选择定时器2为串口1的波特率发生器
    	ES = 1;                     //使能串口1中断
    	EA = 1;
    	while(1);
    }
    // UART 中断服务程序
    void Uart() interrupt 4
    {	
    	// 接收中断标志位
    	if (RI)
    	{
    		RI = 0;                 //清除RI位
    		SendData(SBUF + 1);     // 把接收的数据+1 再发送出去
    	}
    	// 发送中断标志位
    	if (TI)
    	{
    		TI = 0;                 //清除TI位
    		SendString("发送完成!\r\n");
    	 }
    }
    // 发送串口数据
    void SendData(BYTE dat)
    {
      SBUF = dat;
    	while(TI == 0);
    	TI = 0;
    }
    // 发送字符串
    void SendString(char *s)
    {
        while (*s)                  //检测字符串结束标志
        {
            SendData(*s++);         //发送当前字符
        }
    }

    这个实验就是把接受到的数据+1,再发送出去。

     

    展开全文
  • 51单片机串口通讯为什么给T1附值以后芯片就默认该值为波特率,而不需要其他设置?是跟PCON或者SCON有关吗以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下...

    51单片机串口通讯为什么给T1附值以后芯片就默认该值为波特率,而不需要其他设置?是跟PCON或者SCON有关吗以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

    ab98f24f25eea70f3629c14298fac7c2.png

    51单片机串口通讯为什么给T1附值以后芯片就默认该值为波特率,而不需要其他设置?是跟PCON或者SCON有关吗

    当然有关了,PCON决定波特率是否加倍,不设置是不加倍,SCON决定串口工作方式如接收位数及有没有时钟等

    为什么CC2530芯片无法与51单片机进行串口通讯

    CC2530内部就有8051内核呀,不用别配单片机呀。

    51单片机用定时器T1或T2作为波特率发生器,为什么不用T0。

    51单片机只有 T1、T0,没有T2(52才有)。

    如果工作在方式0,方式1、方式2 的话,51单片机的T0、T1都可以做波特率发生器(一般是方式2做波特率发生器)。但是T0可以工作在方式3,T1不能工作在方式3。这种情况下,只能用T1作为波特率发生器,T1 的资源TF1、TR1给了t0,t0工作在方式3,可以当做定时器、计数器用。而如果用t0做波特率发生器,因为T1不能工作在方式3,方式3就没法用了。

    51单片机串口通讯程序 使用12M晶振 单片机没有1T模式 波特率为9600 那位哥们知道给点提示也好啊 先谢了

    12m/9600=1250你需要的就是把时钟分频与波特率的分频设置好,是他们相乘等于1250.分频的设置应该都在时钟的寄存器与串口通讯的寄存器里吧。

    51单片机串口通讯,单片机为什么只能接收一次指令

    51单片机的串口通讯,单片机当然不可能只接受一次指令,如果只能接受一次指令,那么应该是程序有问题。

    51单片机ct107d单片机的串口通讯程序怎么写?

    51单片机的串口通讯程序编写步骤是:

    1、初始化串口相关的寄存器。

    2、可以用中断模式,也可以用查询模式,取决于应用场合。

    3、收发数据取决于标志位TI和RI。

    举例如下:

    #include

    #define uchar unsigned char

    main()

    {

    uchar tmp,t;

    TMOD=0x20; 初始化

    SCON=0x50

    TH0=0xfd;

    TL0=0xfd;

    TR1=1;

    while(1)

    {

    if(RI) 如果有串口数据传来

    {

    tmp=SBUF; 接受数据

    t=100;

    while(t--);

    SBUF=tmp; 将数据回传

    while(TI);

    TI=0;

    }

    }

    }

    MCS_51单片机串口按波特率为1.2KHZ工作,试确定定时器t1的初始值,晶振fosc=12Mhz

    fosc = 12MHz,于是系统时钟fsys = 12MHz/12 = 1MHz

    若按1.2kHz工作,则定时周期为1MHz/1.2kHz ≈ 833

    因此T1初始值应为65536 - 833 = 64703 = FCBFh,因此TH1 = 0xFC,TL1 = 0xBF。

    430单片机串口波特率的最大最小值是什么算的

    多数430配置的串口有2种,UART和SPI。

    UART的波特率的设置方法,要参考数据手册的UART部分,有个配置表,在不同的时钟速度配置根据表里的参数直接配置就行。从最小波特率到最大,都很详细。

    SPI的波特率的只有工作在主机模式才需要设置,具体方法只需要参照数据手册的计算公式,同样是根据时钟速度进行简单的除法。

    为什么CC2530芯片无法与51单片机进行串口通

    硬件连接要正确,然后就是软件编程支持

    芯片的硬件电路没问题的前提下,再设置串口通信参数,双方通信的参数必须一致才行。

    51单片机的最高波特率只能是19200吗?

    不止,可以57600

    晶振11.0592M

    TMOD=0x20

    SCON=0x50

    TH1=0xff

    PCON=0x80

    分页:123

    展开全文
  • 51单片机串口通信

    2021-01-06 04:54:53
    使用串口通信,需要对SCON、PCON和TMOD三个特殊寄存器进行配置。 SCON 串口工作方式寄存器SCON(98H)的结构如下表所示: SCON 位 7 6 5 4 3 2 1 0 意义 SM0 SM1 SM2 REN TB8 RB8 TI RI SM2:多机通信控制...
  • 串口编程(python串口通信实例)

    千次阅读 2021-03-05 14:11:07
    串口编程是个什么东西?串口编程用于工业控制,PC侧可利用MSCOMM控件或WIN API函数操作串口(RS232口)与外设进行通信,命令外设执行某种操作,获取外设返回的数据,进行数据处理.我想通过串口调试助手给单片机发1-30...
  • 2、51单片机串口 和定时器冲突问题

    千次阅读 2021-05-03 20:45:26
    1、整体的一个通讯框架 串口接收信息然后在主函数中不断的扫描接收状态位置 2、具体的见代码所示 3、主函数代码 主要循环扫描86步进电机运行 #include "STC8051.h" #include "Uart.h" #include "Common.h" #include ...
  • 串口通讯

    2021-01-06 08:11:47
    串行口控制寄存器SCON和PCONa>.**串行控制寄存器** **SCON**b>.**串行控制寄存器** **PCON**2).串行口数据缓冲寄存器SBUF3).从机地址控制寄存器SADEN/SADDR4).串行口中断相关寄存器IE/IPH/IPa>.中断允许寄存器IEb...
  • PCON主要是为CHMOS型单片机的电源控制而设置的专用寄存器,单元地址是87H,其结构格式如下:PCOND7D6 D5 D4 D3D2D1 D0位符号 SMOD ---GF1 GF0 PD IDL在CHMOS型单片机中,除SMOD位外,其他位均为虚设的,SMOD是串行口...
  • 串口通信的原理串口通信(SerialCommunicaTIons)的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现...
  • 单片机 串口编程之串口通信仿真实验

    万次阅读 多人点赞 2018-11-17 18:28:24
    单片机 串口编程之串口通信仿真实验 一、简述 记--简单的使能串口串口收发数据的例子。(使用Proteus仿真+虚拟串口调试) 代码,仿真文件打包:链接: https://pan.baidu.com/s/1nyb46fTJrYcAy_VarFdO3A 提取...
  • TXD(P3.0)发送数据 Transmit(tx) Data 简写形式 RXD(P3.1)接受数据 Receive(rx) Data 简写形式 串行口的控制寄存器共有两个:特殊功能寄存器SCON和PCON。下面介绍这两个特殊功能寄存器各位的功能。 2.1.1、...
  • PCON = 0x00; // 波特率不倍增 TR1 = 1; // 启动定时器1 while(1) { if(RI == 1) // 是否有数据到来 { RI = 0; data1 = SBUF; //P1 = data1; // 数据传送到P0口 // send_char(data1); // 回传...
  • Proteus串口通信

    千次阅读 2020-06-01 11:00:59
     主要介绍如何在proteus中搭建串口通讯电路,然后在PC中使用串口助手和proteus中的MCU进行通信。 2.主要使用到的软件  ① Proteus  Proteus是由Lab Center Electronics公司推出的电子设计自动化(EDA)软件。除...
  • 52单片机串口通讯

    2021-03-05 21:49:13
    串口通讯 基本概念 数据帧:就是在线路上传递的一组数据,这组数据可大可小。以电子,无线为介质传输。(对应OSI网络7层模型中的数据链路层) 比特率:在1秒钟所传递的bit数量。(bit/s) 波特率:一秒内的...
  • STC学习:串口通信

    2021-08-03 10:31:48
    程序设计目标:本实验实现的是红外单工方简单上下位机串口数据的发送与接收。单片机通过按键2、3调整发送的数据(0~F),按键1控制数据发送给上位机,并在串口助手的接收数据缓存区显示;上位机设定发送缓存区数据...
  • 文章目录前言一、计算机通信简介二、串口通信简介1、简介2、同步通信和异步通信2.1 同步通信2.2 异步通信3、串行通信的传输方式4、串口通信硬件电路5、常见接口介绍三、串口相关寄存器详解1、特殊功能寄存器SCON2、...
  • 51单片机-串口-串口发送显示 1. 视频 bilibili视频地址: ...PCON电源管理寄存器 SCON串口控制寄存器 模式&波特率(宋雪松P183) SCON主要用模式1,的波特率 对应的,要用定时器T1&T2的模式2...
  • TMOD、TCON、SCON、PCON、SBUF寄存器说明

    千次阅读 多人点赞 2021-01-06 13:39:23
    PCON:电源控制及波特率选择寄存器 电源控制寄存器PCON中只有一位SMOD与串行口工作有关, SMOD:波特率倍增位。串行口工作在方式1、方式2、方式3时,若SMOD=1,则波特率提高一倍; 若SMOD=0,则波特率不提高一倍。...
  • PCON全称Power Control Register,即功率控制寄存器,我们在配置51单片机中的波特率的时候会用到它,其各位如下    系统复位默认为SMOD=0。当用51单片机的定时器2产生波特率时,波特率不受SMOD的影响。  各位...
  • //如果串口1接收到数据,将此数据由串口2发送  if(flag1==1)  {    flag1=0;  UART_2SendOneByte(temp1);    }  delay(300);  P0=temp1; //如果串口2接收到数据,将此数据由串口1发送 ...
  • 51串口实验

    2014-07-03 17:44:45
    51单片机串口程序 void UsartConfiguration() { SCON=0X50; //设置为工作方式1 TMOD=0X20; //设置计数器工作方式2 PCON=0X80; //SMOD=1,波特率加倍 TH1=0XF3; //计数器初始值设置,注意波特率是4800的 ...
  • 单片机串口通讯在12MHz下的问题

    千次阅读 多人点赞 2020-07-09 17:15:55
    单片机串口通讯在12MHz的问题 首先想说单片机的12M远不如11.0592M,其问题之大折磨了我一下午 我使用的板子是普中的,他的单片机的晶振就是12Mhz,虽然我知道12Mhz在计算波特率时会有误差,但我没想到这个误差会有...
  • proteus虚拟串口实现

    千次阅读 2020-03-04 04:21:07
    文章目录1.概述2.主要用到的软件说明3.创建虚拟串口对4.搭建Proteus仿真电路① 电路示意...主要介绍如何在Proteus中搭建串口通讯电路,利用VSPD软件虚拟一对串口,然后在PC中使用串口助手和Proteus中的MCU进行通信...
  • Keil C51 中使用Printf()进行串口输出。

    千次阅读 2018-11-02 10:19:30
    如何使用printf在串口显示信息,有两种办法,因为在keil C51中 printf函数是调用putchar进行数据传送的,而putchar应该是先判断TI是否为1,不为1则等待为1。如果为1则清0,然后送出一个字符。因此如果你直接使用...
  • 51单片机之串口通信详解

    千次阅读 多人点赞 2020-10-05 19:36:02
    串口通信一、串口通信概念1、串口通信的作用2、串口通信的通信方式 一、串口通信概念 1、串口通信的作用 串口通信主要用于单片机与外部设备的通信。51单片机自身有圈双工的异步通信串口。 2、串口通信的通信方式 ...
  • 串口通信 串口 串口是一种十分广泛的通讯接口,可实现两个设备的互相通信。 单片机的串口可以使单片机与单片机,单片机与电脑,单片机与各式各样的模块相互通信,极大的扩展了单片机的应用范围,增强了单片机系统的...
  • 51单片机——串口1收发

    千次阅读 2021-03-16 10:50:24
    修改串口初始化,不加这几个没法接收 TI=0; RI=0; REN=1; //不开启这个无法接受数据 //PS=1; //提高串口中断优先级 ES=1; //开启串口中断使能 EA=1; 2.问题 修改后发现有不合理的地方,待后期修改,如下图...
  • 51单片机默认使用定时器1作为串口通信的波特率发生器、定时器1中断通信,串口与定时器1冲突,在遇到定时器不够用的时候可以用定时器2
  • stc12c5a60s2串口程序

    2021-07-26 00:14:22
    描述用过stc12C5A60S2单片机的朋友都知道,该单片机有两个串口可用,看到官网的程序注释的也是比较多,所以自己写了个串口2使用的程序,由于代码相对简单,所以这里只罗列出了串口2的的初始化、发送和接收函数供大家...

空空如也

空空如也

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

串口pcon