“串口通信”

示波器查看串口注意地方:

(1) RS232电平的定义是:-15V~-3V代表“1”,+3V~+15V代表“0”。

(2) 低位在前,高位在后

(3) TTL:无数据时候,都是高电平,起始位为低电平,停止位为高电平;RS232反之

(4)每个字节头和尾都要加起始位(低电平)和结束位(高电平)

 (5)9600波特率相当1byte/ms ,115200波特率相当10byte/ms

(6)非级联串口TX配置推挽方式;级联串口TX配置漏极开路方式

波特率9600bps, 9600/10=960Bps(包含起始位和停止位),  大约1ms一个字节时间

 

串口工作原理:

一般CPU会采用8倍或16倍的波特率的速率采样。采用下降沿触发,进行过采样,并对中间的几个采样值进行判断,如果大部分一致则认为正确,否则会认为出错,有NOSIE,会把寄存器某一位置1。

 

串口超时机制(上位机):

// 接收时,两字符间最大的时延
comTimeOut.ReadIntervalTimeout = 3;

// 读取每字节的超时
comTimeOut.ReadTotalTimeoutMultiplier = 3;

// 读串口数据的固定超时
// 总超时 = ReadTotalTimeoutMultiplier * 字节数 + ReadTotalTimeoutConstant

 

 9位串口通信:

  (1)  第9位(即最高位)--表示地址/数据信息(0:表示前8位为数据; 1:表示前8位为地址).即当串行数据第9位为“1”时,前8位数据指示的是用来和主机通讯的从机地址;当串行数据第9位为“0”时,前8位数据则用为真正的数据

  (2)  对PC串口调试助手来说校验位就是第9位。---(mark校验(校验位固定是1)或者space校验(校验位固定是0)),可基于此编写9位串口调试助手

  (3)  一般机制,对从设备接收来说,只有接收到与自己地址匹配的才会跳入中断,接收的第一个字节数据即是地址数据,而后再接收实际数据;对从设备发来说,首先要发自己地址数据信息,再发实际数据。

 (4)从设备采用漏极开路方式级联,从设备的串口TX必须配置为漏极开路,不能是推挽方式,如果配置成推挽方式,会导致灌电流过大,低电平低不下去问题

 

 

“串口通信”_第1张图片

“串口通信”_第2张图片

 

一般主要2,3,5三个引脚连接就可以通信。(2为接收,3为发送,5为地。注意这里的接收和发送都是对外端(例如PC来说),就是PC的接收和发送,理解这一点对用交叉还是直通串口线就不会混淆了)

 

一般来说:板子是公头采用交叉串口线,板子是母头采用直通串口线 (PC机是公头)

 一般采用查询发送(循环发送)方式:  
unsigned char Send[10];                  //发送量  
unsigned char i;                         //循环量  
for(i = 0; i < 10; i++)  
{  
    SBUF = Send[i];                   //发送  
    while(TI == 0);                   //等待发送完成  
    TI = 0;                           //清标志  
}  
       
采用中断发送方式:  
unsigned char Send[10];                  //发送量  
unsigned char num;                       //发送数据量  
unsigned char *p;                        //发送用指针  
       
//发送时:  
num = 10;                                //定义发送数据量  
p = &Send ;                              //取首地址  
SBUF = *p;                               //发送第一个数据,启动发送中断  
//中断代码:  
void ComInt() interrupt 4  
{  
    if(RI)  RI = 0;                   //接收中断略;  
       
    if(TI)                            //发送中断处理  
    {  
        TI = 0;                    //清标志  
        num--;                     //计数减1  
        p++;                       //指针加1  
        if(num > 0) SBUF = *p;     //数据继续发送至全部发完  
    }  
}


例如通信协议格式:EF + LEN  + DATA1......+DATAN + SUM 

LEN (DATA1.....SUM)

SUM(EF..........DATAN)

 

1.查询方式的应用:

  

bit WaitUART()   
{
 unsigned int xdata wait_j;
   for(wait_j=0;wait_j<4000;wait_j++) //374-0.58,500-0.8ms,600-0.9,700-1.08,800-1.18,900-1.36,1100-1.6ms 
   {          
       if(RI1==1)
          {
    ClearRI1
              return 1;
          }
   }
   return 0;
}

 

void  uart1_isr() interrupt 20                      //UART1 INTERRUPT
{
    register unsigned char Redata;
 unsigned char m;
    unsigned char CheckReSum=0;
   
    EA = 0;                //disable all interrupt;

    if(!WaitUART()) goto Exit;
 Redata = SBUF1;
    if(Redata != 0xef)           // check receive flag
    {
     goto Exit;
    }

    if(!WaitUART()) goto Exit;
    Redata = SBUF1;
    if(Redata == 0)  
    {
     goto Exit;
    }
    iCmddata[0]=Redata;     //data length
   
    CheckReSum = 0xef + iCmddata[0];
    for(m=1;m<iCmddata[0];m++)            
 { 
    if(!WaitUART()) goto Exit;
       Redata = SBUF1;
       iCmddata[m] = Redata;
       CheckReSum += Redata;
 }
     
    if(!WaitUART()) goto Exit;
    Redata = SBUF1;
    iCmddata[m] = Redata;         //sum
   
    if(CheckReSum != iCmddata[m])   //check transdata sum
    {
   goto Exit;
 }

 ProcessOrder();

 Exit:
   EA = 1;          //enable all interrupt
}

优点:对包响应的实时性要好

缺点: 由于采样查询方式,CPU一直等数据接收完(不像中断),占用CPU时间,对于大数据量的传输,这个缺点尤其明显。

 

2.中断方式(采用队列)

   (1)定义的一个数组用来接收数据,数据满的时候,最前面的数据会被最新的数据替换。

   (2)有两个指针,一个头指针,由用户控制,用来查找符合包格式的数据包;一个尾指针永远指向队列的末尾处

 

 如何查找:当发现头指针和尾指针不相等时,说明有新的数据,头指针向后移动,取出数据。

               (1)如果数据不符合格式,头指针回到最初的位置+1

               (2)如果数据符合格式,但未接收完,当头指针和尾指针相等,头指针返回最初的位置。

 

优点: 不占用CPU资源,对大数据量传输比较好

缺点:   对包响应的实时性要差,依靠用户从队列取包,没有超时判断,容易包误判。

问题:

   假设发送 (1)第一个包发送 EF

                 (2)第二个包发送 EF 02 10 01

  队列的数据就为

               EF EF 02 10 01

 由于队列没有超时机制,只是将接收的数据依次放在队列中。当在队列取数据的时候,当取出EF后,会将后面的EF当成LEN,当取到最后值01时候,头指针会回到当初的EF头处 (认为数据没接收完),这样对第二个包就没有响应了。

 

解决方法:

  如果第一字节出现AB 第二字节再从头一帧数据,那程序肯定无法判断,这是避免不了的。但如果发一字节AB后间隔一断时间,可以用定时器限制来判断,接收到字节时开始计时,如果超过一定时间,定时器中断对接收队列指针回0。 

 

3.中断方式(开启定时器等待)

   当串口接收到第一个数据时候(通常是包头),如果包头正确的话,开启一个定时器开始计数。当定时器规定时间(即接收串口数据最长包的时间)到达的时候,设置一个标志表示数据接收完毕。 在程序主循环不断判断这个标志,如果标志被置1,则进行相应处理,处理完后再将该标志清零。

void UsartIsr0() interrupt 4

{
  EA=0;
      if(SCON0&0x01)
    {
        SCON0&=0xFE;
  Usart0Buff = SBUF0;
  if(RxIndex0 >=80) RxIndex0 = 0;
        RxBuff0[RxIndex0++] = Usart0Buff;
  DataLength0 = RxIndex0;
  Time1Flag = 0;
  TR1 = 1;
  }
 SCON0&=0xFE;
 EA=1;
}

 

void Timer1_ISR (void) interrupt 3
{
    //EA=0 ;
    Time1Flag ++;
 if(Time1Flag >2)// &&(RxIndex2>4))
 {
  Time1Flag = 0;
  usart0_RxFlag=1;
  RxIndex0=0;
  TR1 = 0;
 }
    //EA=1 ;
}    

 

void main(void)

{

   ......

   while(1)

 {

   if(usart0_RxFlag) 

   {
     ............................

     usart0_RxFlag = 0;

   }

 }

}

 

优点: 不占用CPU资源,有超时判断

缺点:   定时器设置时间不好确定,导致小数据包和大数据包的响应时间都一致。        

你可能感兴趣的:(timer)