2019-01-15 23:06:18 qq_37007823 阅读数 858
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6005 人正在学习 去看看 朱有鹏

一、完整工程参考:示例工程源码(点击下载@akoc)

二、源码展示:

#define USART_RX_LEN 20  //接收缓存长度(请勿超过芯片rom剩余空间大小)  
#define USART_TX_LEN 20  //发送缓存长度                                                                
typedef struct      //串口相关结构体定义(主要用于接收):
{
    u8 RX_BUFF[USART_RX_LEN]; //接收缓存
    u8 TX_BUFF[USART_TX_LEN]; //发送缓存
    u16 RX_COUNT;
}USART;
USART Usart;

void USART_Configure(u16 BaudRate) //初使化函数  输入参数:波特率
{
    u8 TH1_Dat;
    
  switch(BaudRate) //采用switch提高可读性
    {
      case 1200:  TH1_Dat=0xE8; break;
        case 2400:  TH1_Dat=0xF4; break;
        case 4800:  TH1_Dat=0xFA; break;
        case 9600:  TH1_Dat=0xFD; break;
        case 14400: TH1_Dat=0xFE; break;
    }
    TMOD &= 0x0F;//先清除再配置
    TMOD |= 0x20;
    SCON &= 0x0F;
    SCON |= 0x50;
    TH1 = TH1_Dat;
    TL1 = TH1;
    PCON = 0x00;
    EA = 1;
    ES = 1;
    TR1 = 1;  
}

void USART_SendByte(u8 dat) //单字符发送
{
    SBUF=dat;
    while(!TI);  //等待发送数据完成
    TI=0;                //清除发送完成标志位
}
void USART_Send(u8* arr,u16 len)//多字符发送
{
  u16 i;
    for(i=0;i<len;i++)
    {
        SBUF=arr[i];
      while(!TI);  //等待发送数据完成
      TI=0;                //清除发送完成标志位  
    }
}
void USART_SendStr(u8* str)//字符串发送
{
  while(1)
    {
      if(*str=='\0') break;
        SBUF=*str++;
        while(!TI);  //等待发送数据完成
      TI=0;                //清除发送完成标志位
    }
}

void USART_IRQHandler(void) interrupt 4  //串口中断函数
{          
  if(RI==1)    //判断是否为接收中断(串口中断分为发送中断和接收中断,均用同一个中断服务函数入口)
    {
        RI = 0;    //清除RI硬件接收中断标志 
        Usart.RX_BUFF[Usart.RX_COUNT++]=SBUF;
        if(Usart.RX_COUNT==USART_RX_LEN) Usart.RX_COUNT=0;
    }    
}

//示例:

/*Uart串口发送函数示例:
1.USART_SendByte(u8 dat) //发送单字节数据
  例:USART_SendByte(0x04);

2.USART_Send(u8* arr,u16 len) //发送多字节数据
  例:
  Usart.TX_BUFF[0]=0xA1;
  Usart.TX_BUFF[1]=0x08;
  Usart.TX_BUFF[2]=0x04;
  Usart.TX_BUFF[3]=0xF9;
  USART_Send(Usart.TX_BUFF,4);
  或
  u8 Arr[16]={0xA1,0x08,0x04,0xF9};
  USART_Send(Arr,4);

3.USART_SendStr(u8* str) //发送字符串数据
  USART_SendStr("大吉在利,晚上吃鸡!\r\n");


Uart串口接收函数示例:
 

//1.单字符指令接收:

#include "reg51.h"
void main(void)
{
   USART_Configure(9600);//配置9600波特率(默认无奇偶校验,1位停止位,8位数据位)
   while(1)
     {
       if(Usart.RX_COUNT>0) //判断串口是否有接收
         {
           Usart.RX_COUNT=0;
             if(Usart.RX_BUFF[0]=='A') //如果控制对象比较多请换成switch()
             {
               P1=0x0F;
             }
             if(Usart.RX_BUFF[0]=='B')
             {
               P1=0xF0;
             }
         }
     }
}

//2.多字符指令接收:(为了方便,我们用C标准库自带的string.h)
#include "reg51.h"
#include <string.h>
void main(void)
{
   char xbuff[20];
   USART_Configure(9600);//配置9600波特率(默认无奇偶校验,1位停止位,8位数据位)
   while(1)
     {
       if(Usart.RX_COUNT>4) //判断串口是否接收到指令(设指令格式为:开灯/  关灯/  用/来表示指令结束符)
         {
           if(Usart.RX_BUFF[4]=='/') //断判结束符
             {
                 Usart.RX_COUNT=0;
                 strncpy(xbuff, Usart.RX_BUFF+0 , 4);//+0表示从接收缓存的第0个字符开始截取4个字符到xbuff判断指令
                 if(strncmp(xbuff,"开灯",4) == 0) 
                 {
                   P1=0x01;
                 }
                 if(strncmp(xbuff,"关灯",4) == 0) 
                 {
                   P1=~0x01;
                 }
             }
             else
             {
               Usart.RX_COUNT=0;
             }
     }
}

 

2010-12-04 16:20:00 kulung 阅读数 3198
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6005 人正在学习 去看看 朱有鹏

单片机RS-485串口通信

RS-485是半双工的通信方式,发送和接收共用同一物理信道。在任意时刻只允许一台单机处于发送状态。因此要求应答的单机必须在侦听到总线上呼叫信号已经发送完毕,并且没有其它单机发出应答信号的情况下,才能应答。半双工通信对主机和从机的发送和接收时序有严格的要求。如果在时序上配合不好,就会发生总线冲突,使整个系统的通信瘫痪,无法正常工作。要使总线上的设备在时序上严格配合。在复位时,使主从机都处于接收状态。

MAX3082的发送和接收转换是由芯片的 RE/DE端控制的。RE/=1DE=1时,MAX3082处于发送状态;RE/=0DE=0时,MAX3082处于接收状态。一般使用单片机的一个IO口连接RE/DE端。在上电复位时,由于硬件电路稳定需要一定的时间,并且单片机各端口复位后处于高电平状态,这样就会使总线上各个分机处于发送状态,由于上电时各电路不稳定,可能向总线发送信息。因此,如果用一根口线作发送和接收控制信号,应该将口线反向后接入MAX3082的控制端,使上电时MAX3082处于接收状态。另外,在主从机软件上也应做处理措施,如:上电时或通信之前,对串行口做几次空操作,清除端口的非法数据和命令。

RS-485的通信程序编写和RS-232没有太大区别,如果使用一个IO口控制MAX3082RE/DE端口, RS-485只比RS-232多了一个接收和发送的转换控制位。初始化串口时,使该位处于低电平,即接收状态。发送数据时,使该位先为高,发送完数据后拉低。程序如下:

 

sbit  RS485_E  P3^5     //发送,接收控制位

 

void UART1_Init(void)

{

      SCON = 0x50;           //方式18位数据,可变波特率

 

      RS485_E      = 0;        //置低,接收

 

      TMOD|= 0x20;           //定时器1,方式28位自重载

      PCON = 0x00;           //波特率倍频禁止

      TH1  = 0xfd;             //晶振22.1184MHz,波特率19200;

      TL1  = 0xfd;             

      IE      |= 0x90;                  //开中断

      IP     = 0x10;

      TR1  = 1   ;            //启动定时器

}

 

void UART1_Send_Char(const INT8U dt)

{   

      SBUF    = dt;

      while(!TI);           

      TI = 0;

}

 

void UART1_Send_String(INT8U *str, INT8U len)

{

      INT8U i;

      RS485_E      = 1;        //置高,发送

      ES          = 0;

      for(i=0; i<len; i++)

      {

             UART1_Send_Char(*(str+i));  

      }

      RS485_E      = 0;        //置低,接收

      ES          = 1;                     

}

 

void UART1_Interrupt(void) interrupt 4        

{

      RS485_E = 0;             //接收   

      ES = 0;

      if(RI)                                 

      {

             //中断接收数据

      }

      ES = 1;

}

 

 

2015-03-14 22:54:32 ipdome_lovelyfat 阅读数 360
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6005 人正在学习 去看看 朱有鹏
  
  /*串口参数配置*/
  USART_InitStructure.USART_BaudRate = 115200;                 /*设置波特率为115200*/
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;  /*设置数据位为8位*/
  USART_InitStructure.USART_StopBits = USART_StopBits_1;       /*设置停止位为1位*/
  USART_InitStructure.USART_Parity = USART_Parity_No;          /*无奇偶校验*/    
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; /*没有硬件流控*/
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;      /*发送与接收*/
  /*完成串口COM1的时钟配置、GPIO配置,根据上述参数初始化并使能*/

  STM_EVAL_COMInit(COM1, &USART_InitStructure);
  完成上述配置之后,单片机就会有串口打印了

2009-06-10 11:59:00 zlj800800 阅读数 3706
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6005 人正在学习 去看看 朱有鹏

 

实验四 单片机串口通信实验

    名:郑旅军       号:0656061

指导老师:邹慧兰       绩:

如有疑问,请zlj800800@163.com 探讨

 

一、实验目的

1学习单片机串口工作方式的程序设计

2学习串行通信的协议

3学习串口通信的中断方式的程序编写方法

二、实验内容

1利用单片机串口,实现两个实验台之间的串行通信。

2一个试验箱自发自收

三、实验预备知识

四、程序框图:自己设计程序框图

 

五、实验步骤

1按要求编写相应的程序

(1)自发自收程序

 zfzs.c

 

#include "reg51.h"

void init(void);

void main(void)

{

P1=0x01;

init();

   SBUF=0x88;

while(1);

 

}

 

void init(void)

{

SCON=0x40;       //工作方式1 ,并置REN=1,接收使能

      REN=1;               //上命令可分写为SCON=0x40;REN=1

    TMOD=0x20;       //定时器1 ,工作模式2

    PCON=0x80;       //SMOD=1,串行口波特率倍增,自动重载;

    TH1=0xF3;       //设置波特率

    TL1=0xF3;

    EA=1;

     ET1=1;

    ES=1;       //串口中断使能

    TR1=1;          // 启动定时器1

}

 

void serial() interrupt 4

{

 

 

if(RI)     //RI=1表示接收完成

{

    RI=0;

 P1=SBUF;   //接收完立刻取走数据

 

}

else

    TI=0;

}

(2)双机通信程序

发送端程序:

f.c

#include "reg51.h"

 

void init(void);

void delay();

void main(void)

{

init();

 

while(1)

{

 

SBUF=0x88;

delay();

}

 

}

 

void init(void)

{

SCON=0x40;       //工作方式1 ,并置REN=1,接收使能

      REN=1;               //上命令可分写为SCON=0x40;REN=1

    TMOD=0x20;       //定时器1 ,工作模式2

    PCON=0x80;       //SMOD=1,串行口波特率倍增,自动重载;

    TH1=0xF3;       //设置波特率

    TL1=0xF3;

    EA=1;

     ET1=1;

    ES=1;       //串口中断使能

    TR1=1;          // 启动定时器1

}

void delay()

{int j,k;

 for(k=10000;k>0;k--)

 for(j=5000;j>0;j--);

}

 

void serial(void) interrupt 4

{

 

 

    TI=0;    //继续发

}

接收端程序:

s.c

#include "reg51.h"

 

void init(void);

void main(void)

{

init();

P1=0X01;

while(1);

}

 

void init(void)

{

SCON=0x40;       //工作方式1 ,并置REN=1,接收使能

      REN=1;               //上命令可分写为SCON=0x40;REN=1

    TMOD=0x20;       //定时器1 ,工作模式2

    PCON=0x80;       //SMOD=1,串行口波特率倍增,自动重载;

    TH1=0xF3;       //设置波特率

    TL1=0xF3;

    EA=1;

     ET1=1;

    ES=1;       //串口中断使能

    TR1=1;          // 启动定时器1

}

 

void serial(void) interrupt 4

{

char i;

if(RI)

{

    RI=0;    //继续收

    i=SBUF;

    P1=i;

}

 

}

2连接实验电路图

 

3调试并运行程序,观察结果

本次实验我是设计了先给P1口赋一个初值,使之有初状态(这里我使LED1灯亮),然后将一个数据(这里是0x8080H)送给SBUF,经TXD送出,再经RXD接收,数据接收完后,再次送到P1 口,这样就显示一个新的状态(LED3LED7灯亮)。

六、实验总结

  本次实验花费了不少的时间,在没有去实验室上机实验前就已经按自己对串口中断过程的理解把程序写好了,但是没有想到我的思路有错,所以在实验箱上反复的修改、运行程序都没有得到期望的结果。后来在老师的指导下,对串口中断理解重归正确,得到了正确结果。

  接下来,我计划把程序完善,使程序能够发送一个字符串,并使LED灯循环点亮。

Tr.c

#include "reg51.h"

#define uchar unsigned char

unsigned int n;

unsigned char a[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

void init(void);

void delay();

void main(void)

{

 

init();

 

while(1)

{

 

SBUF=a[n];

n++;

while(!TI);

TI=0;

if(n==7)

n=0;

delay();

}

}

 

 

 

void init(void)

{

SCON=0x40;       //工作方式1 ,并置REN=1,接收使能

      REN=1;               //上命令可分写为SCON=0x40;REN=1

    TMOD=0x20;       //定时器1 ,工作模式2

    PCON=0x80;       //SMOD=1,串行口波特率倍增,自动重载;

    TH1=0xF3;       //设置波特率

    TL1=0xF3;

    EA=1;

 

    ES=1;       //串口中断使能

    TR1=1;          // 启动定时器1

}

void delay()

{int j,k;

 for(k=10000;k>0;k--)

 for(j=5000;j>0;j--);

}

 

 

void serial() interrupt 4

{

 

if(RI==1)

{

 

RI=0;

P1=SBUF;

 

 

}

else

TI=0;

}

2011-02-23 09:02:00 khbird 阅读数 528
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6005 人正在学习 去看看 朱有鹏

    今天编写了一个简单的单片机串口通信的程序,用串口调试助手调试程序,一直得不到所要的结果。以为是程序出了问题,但是多次检查程序,实在是找不出问题所在,纠结了半天,最后才知道是串口调试助手的COM端口用错了。用串口调试助手,我没有查看是哪个端口,直接看哪个端口能够打开,就用哪个端口,结果COM3端口可以打开,因此一直用的是COM3端口。但我改为COM4端口时,程序运行很正常。由此看来,以后调试程序时,要多分析原因,而不能仅仅纠结于程序,还要看看硬件等其它可能出错的地方,才能快速找到原因的所在。

 

再次附上自己的小程序:

#include<reg52.h>

 

#define uchar unsigned char

#define uint unsigned int

 

uchar i,m,j;

uint temp0,temp1,speed,getchar,jd;

 

sbit p20=P2^0;

 

/**************************************

函数名称:uart_init

功能: uart初始化函数

参数:无

返回值:无

**************************************/

void uart_init()

{

TMOD=0x20;   //定时器1,工作方式2

 

TH1=0xfd;   //波特率9600 11.0592MHZ

TL1=0xfd;

 

TR1=1;   //开定时器

REN=1;       //允许串行接收

 

SM0=0;   //工作方式1

SM1=1;

     

EA=1;   //开总中断

ES=1;   //开串行中断

}

 

void delay0(uint x)    

{

for(i=3;i>0;i--)

for(j=x;j>0;j--);

}

 

 

//用软件查询方式 

void getspeed()

{

while(!RI)   //等待接收数据完毕

    ;       

RI=0;

}

 

//脉冲产生函数

void jiaodu(uint b)   

{

jd=b;

for(m=30;m>0;m--)

{

p20=1;

delay0(jd);

p20=0;

delay0(600-jd);

}

}

//主函数

void main()

{

uart_init();

while(1)

{

getspeed();

temp0=SBUF;

if(temp0==0xF6)

{

for(i=0;i<4;i++)

{

getspeed();

temp1=SBUF;

if(i==3)

{

speed=temp1;

if (speed<0x10&&speed>=0)                 {getchar=5;P0=0x00;}

         else    if(speed<0x15&&speed>=0x10)     {getchar=10;P0=0x01;}

         else    if(speed<0x20&&speed>=0x15)     {getchar=15;P0=0x02;}

         else    if(speed<0x25&&speed>=0x20)     {getchar=20;P0=0x03;}

         else    if(speed<0x30&&speed>=0x25)     {getchar=25;P0=0x04;}

             else    if(speed<0x36&&speed>=0x30)     {getchar=30;P0=0x05;}

         else    if(speed<0x42&&speed>=0x36)     {getchar=35;P0=0x06;}

         else    if(speed>=0x42)                 {getchar=40;P0=0x07;}

    }

   switch(getchar)

{

case 5:

jiaodu(5);

break;

case 10:

jiaodu(10);

break;

case 15:

jiaodu(15);

break;

case 20:

jiaodu(20);

break;

case 25:

jiaodu(25);

break;

case 30:

jiaodu(30);

break;

case 35:

jiaodu(35);

break;

case 40:

jiaodu(40);

break;

default :

           break;

}

}

}

}

 

 

}

 

 

 

 

 

没有更多推荐了,返回首页