单片机串口转485_单片机串口通信232 485 - CSDN
  • RS232 标准是诞生于 RS485 之前的,但是 RS232 有几处不足的地方: 接口的信号电平值较高,达到十几 V,使用不当容易损坏接口芯片,电平标准也与TTL 电平不兼容。传输速率有局限,不可以过高,一般到一两百千比特每...
    RS232
     标准是诞生于 RS485 之前的,但是 RS232 有几处不足的地方:
    
    1. 接口的信号电平值较高,达到十几 V,使用不当容易损坏接口芯片,电平标准也与TTL 电平不兼容。
    2. 传输速率有局限,不可以过高,一般到一两百千比特每秒(Kb/s)就到极限了。
    3. 接口使用信号线和 GND 与其它设备形成共地模式的通信,这种共地模式传输容易产生干扰,并且抗干扰性能也比较弱。
    4. 传输距离有限,最多只能通信几十米。
    5. 通信的时候只能两点之间进行通信,不能够实现多机联网通信。

    针对 RS232 接口的不足,就不断出现了一些新的接口标准,RS485 就是其中之一,它具备以下的特点:
    1. 采用差分信号。我们在讲 A/D 的时候,讲过差分信号输入的概念,同时也介绍了差分输入的好处,最大的优势是可以抑制共模干扰。尤其当工业现场环境比较复杂,干扰比较多时,采用差分方式可以有效的提高通信可靠性。RS485 采用两根通信线,通常用 A 和 B 或者 D+和 D-来表示。逻辑“1”以两线之间的电压差为+(0.2~6)V 表示,逻辑“0”以两线间的电压差为-(0.2~6)V 来表示,是一种典型的差分通信。
    2. RS485 通信速率快,最大传输速度可以达到 10Mb/s 以上。
    3. RS485 内部的物理结构,采用的是平衡驱动器和差分接收器的组合,抗干扰能力也大大增加。
    4. 传输距离最远可以达到 1200 米左右,但是它的传输速率和传输距离是成反比的,只有在 100Kb/s 以下的传输速度,才能达到最大的通信距离,如果需要传输更远距离可以使用中继。
    5. 可以在总线上进行联网实现多机通信,总线上允许挂多个收发器,从现有的 RS485芯片来看,有可以挂 32、64、128、256 等不同个设备的驱动器。
    6. RS485 的接口非常简单,与 RS232 所使用的 MAX232 是类似的,只需要一个 RS485转换器,就可以直接与单片机的 UART 串口连接起来,并且使用完全相同的异步串行通信协议。但是由于 RS485 是差分通信,因此接收数据和发送数据是不能同时进行的,也就是说它是一种半双工通信。那我们如何判断什么时候发送,什么时候接收呢?

    RS485 转换芯片很多,这节课我们以典型的 MAX485 为例讲解 RS485 通信,如图 18-1所示。
    图 18-1  MAX485 硬件接口
    图 18-1  MAX485 硬件接口

    MAX485 是美信(Maxim)推出的一款常用 RS485 转换器。其中 5 脚和 8 脚是电源引脚;6脚和 7 脚就是 RS485 通信中的 A 和 B 两个引脚;1 脚和 4 脚分别接到单片机的 RXD 和 TXD引脚上,直接使用单片机 UART 进行数据接收和发送;2 脚和 3 脚是方向引脚,其中 2 脚是低电平使能接收器,3 脚是高电平使能输出驱动器,我们把这两个引脚连到一起,平时不发送数据的时候,保持这两个引脚是低电平,让 MAX485 处于接收状态,当需要发送数据的时候,把这个引脚拉高,发送数据,发送完毕后再拉低这个引脚就可以了。为了提高 RS485 的抗干扰能力,需要在靠近 MAX485 的 A 和 B 引脚之间并接一个电阻,这个电阻阻值从 100欧到 1K 都是可以。

    在这里我们还要介绍一下如何使用 KST-51 单片机开发板进行外围扩展实验。我们的开发板只能把基本的功能给同学们做出来提供实验练习,但是同学们学习的脚步不应该停留在这个实验板上。如果想进行更多的实验,就可以通过单片机开发板的扩展接口进行扩展实验。大家可以看到蓝绿色的单片机座周围有 32 个插针,这 32 个插针就是把单片机的 32 个 IO 引脚全部都引出来了。在原理图上体现出来的就是 J4、J5、J6、J7 这 4 个器件,如图 18-2 所示。
    图 18-2  单片机扩展接口
    图 18-2  单片机扩展接口

    这 32 个 IO 口中并不是所有的都可以用来对外扩展,其中既作为数据输出,又可以作为数据输入的引脚是不可以用的,比如 P3.2、P3.4、P3.6 引脚,这三个引脚是不可用的。比如P3.2 这个引脚,如果我们用来扩展,发送的信号如果和 DS18B20 的时序吻合,会导致 DS18B20拉低引脚,影响通信。除这 3 个 IO 口以外的其它 29 个,都可以使用杜邦线接上插针,扩展出来使用。当然了,如果把当前的 IO 口应用于扩展功能了,板子上的相应功能就实现不了了,也就是说需要扩展功能和板载功能之间二选一。

    在进行 RS485 实验中,我们通信用的引脚必须是 P3.0 和 P3.1,此外还有一个方向控制引脚,我们使用杜邦线将其连接到 P1.7 上去。RS485 的另外一端,大家可以使用一个 USB转 RS485 模块,用双绞线把开发板和模块上的 A 和 B 分别对应连起来,USB 那头插入电脑,然后就可以进行通信了。

    学习了第 13 章实用的串口通信方法和程序后,做这种串口通信的方法就很简单了,基本是一致的。我们使用实用串口通信例程的思路,做了一个简单的程序,通过串口调试助手下发任意个字符,单片机接收到后在末尾添加“回车+换行”符后再送回,在调试助手上重新显示出来,先把程序贴出来。

    程序中需要注意的一点是:因为平常都是将 MAX485 设置为接收状态,只有在发送数据的时候才将 MAX485 改为发送状态,所以在 UartWrite()函数开头将 MAX485 方向引脚拉高,函数退出前再拉低。但是这里有一个细节,就是单片机的发送和接收中断产生的时刻都是在停止位的一半上,也就是说每当停止位传送了一半的时候,RI 或 TI 就已经置位并且马上进入中断(如果中断使能的话)函数了,接收的时候自然不会存在问题,但发送的时候就不一样了:当紧接着向 SBUF 写入一个字节数据时,UART 硬件会在完成上一个停止位的发送后,再开始新字节的发送,但如果此时不是继续发送下一个字节,而是已经发送完毕了,要停止发送并将 MAX485 方向引脚拉低以使 MAX485 重新处于接收状态时就有问题了,因为这时候最后的这个停止位实际只发送了一半,还没有完全完成,所以就有了 UartWrite()函数内DelayX10us(5)这个操作,这是人为的增加了 50us 的延时,这 50us 的时间正好让剩下的一半停止位完成,那么这个时间自然就是由通信波特率决定的了,为波特率周期的一半。

    /****************************RS485.c 文件程序源代码*****************************/

    #include <reg52.h>
    #include <intrins.h>
    
    sbit RS485_DIR = P1^7; //RS485 方向选择引脚
    bit flagFrame = 0; //帧接收完成标志,即接收到一帧新数据
    bit flagTxd = 0; //单字节发送完成标志,用来替代 TXD 中断标志位
    unsigned char cntRxd = 0; //接收字节计数器
    unsigned char pdata bufRxd[64]; //接收字节缓冲区
    
    extern void UartAction(unsigned char *buf, unsigned char len);
    
    /* 串口配置函数,baud-通信波特率 */
    void ConfigUART(unsigned int baud){
        RS485_DIR = 0; //RS485 设置为接收方向
        SCON = 0x50; //配置串口为模式 1
        TMOD &= 0x0F; //清零 T1 的控制位
        TMOD |= 0x20; //配置 T1 为模式 2
        TH1 = 256 - (11059200/12/32)/baud; //计算 T1 重载值
        TL1 = TH1; //初值等于重载值
        ET1 = 0; //禁止 T1 中断
        ES = 1; //使能串口中断
        TR1 = 1; //启动 T1
    }
    /* 软件延时函数,延时时间(t*10)us */
    void DelayX10us(unsigned char t){
        do {
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            _nop_();
        } while (--t);
    }
    /* 串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度 */
    void UartWrite(unsigned char *buf, unsigned char len){
        RS485_DIR = 1; //RS485 设置为发送
       
        while (len--){ //循环发送所有字节
            flagTxd = 0; //清零发送标志
            SBUF = *buf++; //发送一个字节数据
            while (!flagTxd); //等待该字节发送完成
        }
        DelayX10us(5); //等待最后的停止位完成,延时时间由波特率决定
        RS485_DIR = 0; //RS485 设置为接收
    }
    /* 串口数据读取函数,buf-接收指针,len-指定的读取长度,返回值-实际读到的长度 */
    unsigned char UartRead(unsigned char *buf, unsigned char len){
        unsigned char i;
        //指定读取长度大于实际接收到的数据长度时,
        //读取长度设置为实际接收到的数据长度
        if (len > cntRxd){
            len = cntRxd;
        }
        for (i=0; i<len; i++){ //拷贝接收到的数据到接收指针上
            *buf++ = bufRxd[i];
        }
        cntRxd = 0; //接收计数器清零
        return len; //返回实际读取长度
    }
    /* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
    void UartRxMonitor(unsigned char ms){
        static unsigned char cntbkp = 0;
        static unsigned char idletmr = 0;
       
        if (cntRxd > 0){ //接收计数器大于零时,监控总线空闲时间
            if (cntbkp != cntRxd){ //接收计数器改变,即刚接收到数据时,清零空闲计时
                cntbkp = cntRxd;
                idletmr = 0;
            }else{ //接收计数器未改变,即总线空闲时,累积空闲时间
                if (idletmr < 30){ //空闲计时小于 30ms 时,持续累加
                    idletmr += ms;
                    if (idletmr >= 30){ //空闲时间达到 30ms 时,即判定为一帧接收完毕
                        flagFrame = 1; //设置帧接收完成标志
                    }
                }
            }
        }else{
            cntbkp = 0;
        }
    }
    /* 串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用 */
    void UartDriver(){
        unsigned char len;
        unsigned char pdata buf[40];
       
        if (flagFrame){ //有命令到达时,读取处理该命令
            flagFrame = 0;
            len = UartRead(buf, sizeof(buf)-2); //将接收到的命令读取到缓冲区中
            UartAction(buf, len); //传递数据帧,调用动作执行函数
        }
    }
    /* 串口中断服务函数 */
    void InterruptUART() interrupt 4{
        if (RI){ //接收到新字节
            RI = 0; //清零接收中断标志位
            //接收缓冲区尚未用完时,保存接收字节,并递增计数器
            if (cntRxd < sizeof(bufRxd)){
                bufRxd[cntRxd++] = SBUF;
            }
        }
        if (TI){ //字节发送完毕
            TI = 0; //清零发送中断标志位
            flagTxd = 1; //设置字节发送完成标志
        }
    }


    /*****************************main.c 文件程序源代码******************************/

    #include <reg52.h>
    
    unsigned char T0RH = 0; //T0 重载值的高字节
    unsigned char T0RL = 0; //T0 重载值的低字节
    
    void ConfigTimer0(unsigned int ms);
    extern void UartDriver();
    extern void ConfigUART(unsigned int baud);
    extern void UartRxMonitor(unsigned char ms);
    extern void UartWrite(unsigned char *buf, unsigned char len);
    
    void main(){
        EA = 1; //开总中断
        ConfigTimer0(1); //配置 T0 定时 1ms
        ConfigUART(9600); //配置波特率为 9600
    
        while (1){
            UartDriver(); //调用串口驱动
        }
    }
    /* 串口动作函数,根据接收到的命令帧执行响应的动作
    buf-接收到的命令帧指针,len-命令帧长度 */
    void UartAction(unsigned char *buf, unsigned char len){
        //在接收到的数据帧后添加换车换行符后发回
        buf[len++] = '\r';
        buf[len++] = '\n';
        UartWrite(buf, len);
    }
    /* 配置并启动 T0,ms-T0 定时时间 */
    void ConfigTimer0(unsigned int ms){
        unsigned long tmp; //临时变量
        tmp = 11059200 / 12; //定时器计数频率
        tmp = (tmp * ms) / 1000; //计算所需的计数值
        tmp = 65536 - tmp; //计算定时器重载值
        tmp = tmp + 33; //补偿中断响应延时造成的误差
        T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节
        T0RL = (unsigned char)tmp;
        TMOD &= 0xF0; //清零 T0 的控制位
        TMOD |= 0x01; //配置 T0 为模式 1
        TH0 = T0RH; //加载 T0 重载值
        TL0 = T0RL;
        ET0 = 1; //使能 T0 中断
        TR0 = 1; //启动 T0
    }
    /* T0 中断服务函数,执行串口接收监控 */
    void InterruptTimer0() interrupt 1{
        TH0 = T0RH; //重新加载重载值
        TL0 = T0RL;
        UartRxMonitor(1); //串口接收监控
    }


    现在看这种串口程序,是不是感觉很简单了呢?串口通信程序我们反反复复的使用,加上随着学习的模块越来越多,实践的越来越多,原先感觉很复杂的东西,现在就会感到简单了。从设备管理器里可以查看所有的 COM 口号,我们下载程序用的是 COM4,而 USB 转RS485 虚拟的是 COM5,通信的时候我们用的是 COM5 口,如图 18-3 所示。
    图 18-3  RS485 通信试验设置和结果
    图 18-3  RS485 通信试验设置和结果
    展开全文
  • 开始我从单片机简单发送一串数据,用串口调试助手测试。上位机根本没有接收到数据,用示波器测了发送管脚和接收管脚都没有波形,查看了下波特率也是对的。所以初步断定是否硬件电路有问题,检查了ADM2483的DE端初始...

    过完年,一到公司主管就催我赶紧把这个项目的PC和单片机的RS485通信给调通。这几天,一直在实验室度过的。开始我从单片机简单发送一串数据,用串口调试助手测试。上位机根本没有接收到数据,用示波器测了发送管脚和接收管脚都没有波形,查看了下波特率也是对的。所以初步断定是否硬件电路有问题,检查了ADM2483的DE端初始化时是低电平,我在程序里把这个位置为高电平,再用万用表测量还是低电平。原来DE和RE和地线是连到一块的,问其他同事,原来他们前面把这个地方拉低为了让485模块一直处于接收状态,测试测试能否接收到上位机数据。把这个地方改过来后,继续测试。还是用简单的串口收发数据测试通信,上位机发送数据,下位机接收到数据后紧接着把接收到的数据发给上位机。测试的时候,发送55和00是正确的,但是其他数据都发生了改变。后面用示波器测试单片机TXD2和RXD2的波形,发现下位机发出的数据在RXD2上显示波形,初步断定是否设计原理图的时候这两个引脚是否反了,把电路板割线,重新跳线调换两个引脚后再测试下位机往上位机发送数据,上位机接收正常。紧接着,发送和接收一起测,发送和接收都正常了。调了几天,原来电路板出问题了,可主管一来就说硬件是没有问题的,让我检查软件。哎,干软件的就是弱势群体,特别在我们公司真是这样。所以搞嵌入式开发的最好要软硬件都懂。最后,我把我以前写的程序下载到板子上,发现仍然和上位机不能通信。最后我想是不是在接收中断函数里通信协议解析不对,通过查阅资,改用另一种方式解析,结果可以通过上位机控制下位机输出显示了。最后把自己些调试用的程序附上:

    简单的串口2收发程序

    #include <reg52.h>
    
    /*******************宏定义***********************/
    #define uchar unsigned char
    #define	uint unsigned int
    /*****************串口2特殊功能的声明*************/
    sfr AUXR=0x8e;  // 辅助寄存器,用于设定串口2工作波特率、独立波特率发生器的选择
    sfr S2CON=0x9a; //串口2串行控制器
    sfr S2BUF=0x9b; //串口2数据缓冲寄存器
    sfr BRT=0x9c;  //独立波特率产生器,重装数
    sfr IE2=0xaf; //串口2中断寄存器
    sfr AUXR1=0xa2;// 辅助寄存器1,用于切换端口。以后用,切记!
    #define	S2RI  0x01 // 串口2接收标志位
    #define S2TI  0x02 // 串口2发送标志位
    sfr WDT_CONTR = 0xc1;//看门狗
    /*******************位定义声明*****************/
    sbit EN1=P3^3;//485通信使能端
    bit flag = 0;
    /********************数据存储、数据缓冲器声明*************/
    
    /**************************************************************/
    //++++++++++++++++++++++++++++++++++++++++//
    //名称:delay_ms
    //作用:延时time毫秒
    //说明:延时函数
    //输入参数:time
    //输出参数:
    //++++++++++++++++++++++++++++++++++++++++//
    void delay_ms(unsigned int time)
    {
       unsigned int i,j;
       for(i=time;i>0;i--)
         for(j=112;j>0;j--)
    	   {;}
    }
    
    uint num;
    void UartInit(void)  //9600bps@11.0592MHz
    {
    	 AUXR &= 0xf7;  //波特率不倍速
    	 S2CON = 0x50;  //8位数据,可变波特率
    	 BRT = 0xFD;      //设定独立波特率发生器重装值
    	 AUXR &= 0xfb;  //独立波特率发生器时钟为Fosc/12,即12T
    	 AUXR |= 0x10;  //启动独立波特率发生器
    	 EA=1;
    	 IE2=0x01;
    }  
    void send(uint ch)
    {
    	EN1 = 1;
    	IE2=0x00;   	
    	S2CON&=~S2TI;  
    	S2BUF=ch;      
    	while(!(S2CON&S2TI));  
    	S2CON &=~S2TI; 
    	IE2=0x01;
    	EN1 = 0;    
    }
    
    void main()
    {
    	EN1 = 0;
    	UartInit();
        send(0x55);
    	delay_ms(1);
    	send(0xaa);
    	delay_ms(1);
    	send(0xff);
    	delay_ms(1);
    	while(1);
     
    }
    void Uart2() interrupt 8        
    { 
    	if(S2CON&S2RI)
    	{
    		S2CON&=~S2RI;
    		delay_ms(1);
    		num=S2BUF;
    		send(num);
    	}
    }
    通信协议解析部分程序

    void Data_analysis(void)
    {
    	static unsigned int check_sum = 0;  //存放校验和
    	static unsigned char lencnt = 0;  //数据长度计数器
    	switch (state_flag)
    	{
    		case 0:
            {
    			if(recdata == 0xaa)     // 是否帧头第一个数据
    				state_flag = 1;
    			else
    				state_flag = 0;    // 标志复位 
    			break;      
            }
           case 1:
           {
    			if(recdata == 0x55)     //是否帧头第二个数据
    				state_flag = 2;
    			else
    				state_flag = 0;    // 标志复位
    			break;
           }
           case 2:
           {
    			if(recdata == addr)     //判断目的地址是否正确
    			{
    				state_flag = 3;
    				check_sum = recdata;
    			}
    			else
    				state_flag = 0;    // 标志复位
    			break;
           }
           case 3:
           {
    			state_flag = 4;
                cmd = recdata;  //指令码
                check_sum ^= recdata;  //校验和累加 
                break;
           } 
           case 4: 
           {
    			lencnt = 0;  //数据长度计数器清零
    			data_count = recdata;  //存储数据长度
    			check_sum ^= recdata;  //累加
    			if(data_count != 0)  //后面有数据码
    				state_flag = 5;
    			else 
    				state_flag = 7;
    			break;
           }        
    	   case 5: 
           case 6: 
           {
    			dat[lencnt++] = recdata;  //存储数据码
    			check_sum ^= recdata;   //累加
    			if(lencnt == data_count)
    			{
    				state_flag = 7;
    				lencnt = 0;        
    			}  				
    			else
    				state_flag = 6;
    			break;
           }
           case 7:
           {
    			if(check_sum == recdata)   //数据校验,判断累加和是否正确
    				state_flag = 8;
    			else
    			{
    			  retval = 1;   //置错误标志,数据传输不正确
    			  state_flag=0;   
    			}
    			check_sum=0;//累加和清0
    			break;
           }
           case 8:
           {
    			if (recdata==0x0d)
    			{
    				retval = 2;   //置接收一帧数据成功标志
    				state_flag=0;
    			}
    			else
    				state_flag=0; 
    			break; 
           }
    	   default:
    			break;
    	}
    // 	if(timeOutFlag == 1)	//超时判断
    // 	{
    // 		timeOutFlag = 0;
    // 		state_flag=0;
    // 		retval = 1;   //置错误标志,数据传输不正确
    // 		recdata = 0x00;
    // 	}
    }


    展开全文
  • RS 485,两线得半双工多点通信,一主机连接多从机 半双工:只能单向的双向通信 概念:半双工(Half Duplex)数据传输指数据可以在一个信号载体的两个方向上传输,但是不能同时传输。在通信过程的任意时刻,信息...

    RS 485,两线得半双工多点通信,一主机连接多从机

     

     

    半双工:只能单向的双向通信

     

    概念:半双工(Half Duplex)数据传输指数据可以在一个信号载体的两个方向上传输,但是不能同时传输。在通信过程的任意时刻,信息既可由A传到B,又能由B传A,但只能有一个方向上的传输存在。采用半双工方式时,通信系统每一端的发送器和接收器,通过收/发开关转接到通信线上,进行方向的切换,因此,会产生时间延迟。

    例如:

    一:在一个局域网上使用具有半双工传输的技术,一个工作站可以在线上发送数据,然后立即在线上接收数据,这些数据来自数据刚刚传输的方向。当某局域网中的两台计算机在实现通信时,同一时刻只能在同一方向上传送数据,这是因为大多数局域网中使用的基带网络都只支持单个信号。换句话说,基带网络采用的是半双工工作模式

     

    二:对讲机就是一种半双工设备,在同一时间内只允许一方讲话。

     

    双工:每一端都可以双向发送、接收,但是不能同时发、收

     

    概念:通信允许数据在两个方向上同时传输,它在能力上相当于两个单工通信方式的结合。全双工方式无需进行方向的切换,全双工指可以同时(瞬时)进行信号的双向传输(A→B且B→A)。指A→B的同时B→A,是瞬时同步的。

     

    例如:我们平时打电话一样,说话的同时也能够听到对方的声音。目前的网卡一般都支持全双工。

     

    单工:死规定,一边发送,一边接收,不能改

     

    概念:数据传输是单向的。通信双方中,一方固定为发送端,一方则固定为接收端。信息只能沿一个方向传输,使用一根传输线

     

    例如;例如计算机与打印机之间的通信是单工模式,因为只有计算机向打印机传输数据,而没有相反方向的数据传输。还有在某些通信信道中,如单工无线发送等。

     

    转载于:https://www.cnblogs.com/cadenBlog-1998/p/10519916.html

    展开全文
  • 串口,作为单片机程序开发中最常用、最方便,也是应用最广泛的程序调试方法;无论是作为调试工具,打印出调试信息,还是对功能模块进行通信,串口是每个单片机开发人员最常用的单片机外设。 由于大部分51单片机不...

    串口,作为单片机程序开发中最常用、最方便,也是应用最广泛的程序调试方法;无论是作为调试工具,打印出调试信息,还是对功能模块进行通信,串口是每个单片机开发人员最常用的单片机外设。
    由于大部分51单片机不支持在线调试功能,所以串口作为一种有效的调试功能,所以在51单片机程序开发时,无法进行在线调试,不妨可以多采用串口来进行调试。
    1.串口配置

    51单片机配置除了需要配置2个8位寄存器SCON、PCON外,还要配置定时器1的控制寄存器TMOD,因为串口在进行收发需要使用定时器来采样。
    (1)状态控制寄存器 SCON
    SCON 是一个逐位定义的 8 位寄存器,用于控制串行通信的方式选择、接收和发送,指 示串口的状态,SCON 即可以字节寻址也可以位寻址,字节地址 98H,地址位为 98H~9FH。 它的各个位定义如下:
    在这里插入图片描述
    SM0 和 SM1 是串口的工作方式选择位,2 个选择位对应 4 种工作方式,如下表,其中 Fosc 是振荡器的频率。
    在这里插入图片描述
    (2)电源与波特率控制寄存器
    控制寄存器 PCON 也是一个逐位定义的 8 位寄存器,目前仅仅有几位有定义,如下所示:
    在这里插入图片描述
    仅最高位 SMOD 与串口的控制有关,其他位与掉电方式有关。PCON 的地址为 87H 只能按 字节寻址,SMOD 是串行通信波特率系数控制位,当串口工作在工作方式 1、2 时,若使用 T1 作为波特率发生器其 SMOD=1 则波特率加倍。
    (3)定时器控制模式寄存器
    TMOD是定时器、计数器模式控制寄存器,它是一个逐位定义的8为寄存器,但只能使用字节寻址
    在这里插入图片描述
    当串口工作在工作方式0和2是,波特率固定,方式0时fosc/12;方式2时fosc/32或fosc/64(根据SMOD判断)。当串口工作在方式1时,波特率=(2^SMOD/32)*(单片机时钟频率/(256-X)),X是初值;C/T#为定时器和计数器选择位,0为定时器,1为计数器

    2.串口通用程序
    为了有较好的通用性,将串口程序配置为一个H文件和C文件,往后只要开发51单片机程序,都可以将该两个文件复制在工程中直接使用,无须修改。
    (1)uart.H

    #ifndef _UART_H_
    #define _UART_H_
    
    #include "reg52.h"
    
    void UartInit(void);
    void Send_string(unsigned char *c);
    void Send_Data(unsigned char DAT);
    
    #endif
    

    (2)uart.c

    #include "uart.h"
    
    //串口初始化
    void UartInit(void)
    {
    	/*串口初始化 */
    	TMOD = 0x20;	  //定时器T1使用工作方式2
    	SCON = 0x50;	  //工作方式1,,允许接收   
    	PCON = 0x10;
    	TH1 = 253;        // 设置初值,波特率9600bps
    	TL1 = 253;
    	TR1 = 1;          // 开始计时	
    	ES = 1;         //打开接收中断
    	EA = 1;           // 打开所以中断   
    	TI = 0;
    	RI = 0;
    }
    
    void Send_Data(unsigned char DAT)
    {
    	ES = 0;
    	TI=0;
    	SBUF = DAT ;
    	while(TI==0);
    	TI=0;
    	ES = 1;
    }
    
    void Send_string(unsigned char  *c)
    {
    	while(*c != '\0')
    	{
    		Send_Data(*c++);
    	}	
    }
    
    void RSINTR() interrupt 4 using 2
    {
    	EA=0;
    	if(TI==1) //发送中断	  
    	{
    		TI=0;
    	}
    
    	if(RI==1)	 //接收中断		  
    	{	
    
    		RI=0;								 
    
    	}
    	EA=1;
    }
    
    

    如需串口参考例程, 请关注公众号,首页回复“串口”获取资料
    在这里插入图片描述

    展开全文
  • 51单片机串口,是个全双工的串口,发送数据的同时,还可以接收数据。 当串行发送完毕后,将在标志位 TI 置 1,同样,当收到了数据后,也会在 RI 置 1。 无论 RI 或 TI 出现了 1,只要串口中断处于开放状态,...
  • 收发状态自动切换的TTL 485 的电路(节省一根IO控制线)1. 对于TTL电平的UART,起始位为低电平,停止位为高电平,发送的数据是从bit0 - bit7,空闲时为高电平。2. 485总线有上拉电阻R40和下拉电阻R45分别上拉到...
  • 51单片机串口通信 环形缓冲区队列最近在做毕业设计刚好涉及到51单片机,简单的研究一下发现51单片机串口只有一个字节的缓存,如果遇到单片机串口中断没有及时处理SBUF的值或者串口中断长时间未退出很容易照成数据...
  • 单片机串口接收的几种常用的数据处理方法 一、为什么串口接收的数据需要处理 我们在做项目的时候经常会用到串口,当我们用串口和别的设备通讯的时候就需要严格遵循通讯协议,然而,仅仅是遵循通讯协议是不够的,因为...
  • 单片机串口通信协议的实现 单片机上的串口是日常调试和做一些简单人机交互的一种重要的通信方式,其原理网上有一大堆,这里就不再赘述了,下面主要和大家分享一种我在实际项目中经常用到的一个简单的串口通信协议...
  • 51单片机串口通信,是全双工的,就是可以同时收/发的,互相不影响的。 串口是可以同时收/发的,虽然都是用SBUF,但却是两个独立的寄存器,互不影响,只是都叫一个名,SBUF。 但是,对于接收或发送,确实是接收到一...
  • 单片机串口调试总结

    2014-10-12 19:45:06
    首先,解决的第一个问题就是计算机与单片机串口通信的数据速率问题即串口通信波特率,这就好比一个豆蔻年华的小姑娘跟她的奶奶讲学校里发生的事情一样,一个生动可爱侃侃而谈,一个听得稀里糊涂却只能点头微笑,所以...
  • 这是我学习PIC单片机调试过程中尝试的PIC单片机串口发送实验,当按键RB0有按下时,num自加,同时RC0端口接的LED翻转,并把num的数传给发送寄存器发送至电脑端,波特率为9600,4M晶振. 代码如下: #include&amp;lt;pic...
  • 在实际应用中,往往串口还要和电脑上的上位机软件进行交互,实现电脑软件发送不同的指令,单片机对应执行不同操作的功能,这就要求我们组织一个比较合理的通信机制和逻辑关系,用来实现我们想要的结果。 本节所...
  • 自:http://bbs.ednchina.com/BLOG_ARTICLE_3007162.HTM ... ... 串口接收程序是基于串口中断的,单片机串口每次接收到一字节数据产生一次中断,然后再读取某个寄存器就可以得到串口接收的数...
  • STC单片机串口收发学习总结1字符串输出到串口2LED闪烁3LED流水灯4定时器5中断6定时与中断应用示例7数码管8串口9RS232接口 1字符串输出到串口 //////////////////////////////////////////////////////// //单片机...
  • 单片机串口通信实例

    2016-06-24 23:53:27
    通过该讲,读者可以掌握单片机串口的工作原理和如何通过程序来对串口进行设置,并根据所给出的实例实现与PC 机通信。  一、原理简介  51 单片机内部有一个全双工串行接口。什么叫全双工串口呢?一般来说,...
  • 51 单片机串口实验

    2016-01-25 11:27:10
    在 PROTEUS 软件中,可以使用虚拟终端,和单片机串口进行通信实验。此时,并不需要在电路中加上 TTL-RS232 电平转换器件。直接把单片机串口,和虚拟终端连接在一起就可以了。但是在一些书中,以及一些网络...
  • 单片机 串口编程之串口通信仿真实验 一、简述 记--简单的使能串口串口收发数据的例子。(使用Proteus仿真+虚拟串口调试) 代码,仿真文件打包:链接: https://pan.baidu.com/s/1nyb46fTJrYcAy_VarFdO3A 提取...
  • 一、为什么要单片机和计算机之间通信需要电平转换? 因为计算机的串口为RS_232C,其中高电平为-12V,低电平为+12V;我们单片机的输出与输入时TTL电平,其中高电平为+5V,低电平为-5V,因此我们需要通过电平转换才能...
  • 关于51单片机串口通信的讲解的博客有很多,这里就不再详细讲解。下面给出程序 1.uart.h #ifndef __UART__ #define __UART__ typedef unsigned char u8; void UART_Init(); void UART_Send_Data(u8 byte); u8 UART_...
1 2 3 4 5 ... 20
收藏数 31,027
精华内容 12,410
关键字:

单片机串口转485