2019-01-18 20:40:57 Easadon 阅读数 225
  • 串口通信和RS485-第1季第13部分

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

    6005 人正在学习 去看看 朱有鹏
#include <ioCC2530.h>
#include <string.h>
#define uint unsigned int
#define uchar unsigned char
// 定义 LED  的端口
#define LED1 P1_0
#define LED2 P1_1

uchar RXTXflag = 1;
char temp;
uchar datanumber = 0;
char Rxdata[52];
void InitLed()
{
  P1DIR = 0x01; //P1_0IO  方向输出
  LED1 = 1; //关 关 LED
}
void InitUart()
{
    CLKCONCMD &= ~0x40;       //设置系统时钟源为 32MHZ晶振
    while(CLKCONSTA & 0x40);  //等待晶振稳定 
    CLKCONCMD &= ~0x47;       //设置系统主时钟频率为 32MHZ   
     
    P0SEL = 0x0c;        //P0_2,P0_3用作串口,第二功能 
    U0CSR |= 0x80;       //UART 方式 
    U0GCR |= 10;         //U0GCR与U0BAUD配合     
    U0BAUD |= 216;       // 波特率设为57600 
    UTX0IF = 1;          //UART0中断标志初始置位1
    U0CSR |= 0X40;       //允许接收 
    IEN0 |= 0x84;       // 开总中断,接收中断    
}

/****************************************************************
串口发送字符串函数
****************************************************************/
void UartSend_String(char *Data)
{
  while(*Data != '\0')
  {
     U0DBUF = *Data++;
     while(UTX0IF == 0);  //the flag of transfer complete
     UTX0IF = 0;
  }
}
/***************************
          主函数
***************************/
void main(void)
{ 
  InitLed(); // 调用初始化函数
  InitUart();
  while(1)
  {
    if(RXTXflag == 1) // 接收状态
    {
      LED1=1; // 接收状态指示
      if( temp != 0)
      {
        if((temp!= '#')&&(datanumber<50))  // # 被定义为结束字符,最多能接收50  个字符
        Rxdata[datanumber++] = temp;
        else
        {
          RXTXflag = 3; // 进入发送状态
          LED1=0; // 关指示灯
         }
        temp = 0;
       }
     }
    if(RXTXflag == 3) // 发送状态
    {
      LED2= 1;
      U0CSR &= ~0x40; // 禁止接收
      UartSend_String(Rxdata);
      U0CSR |= 0x40; // 允许接收
      RXTXflag = 1; //  恢复到接收状态
      datanumber = 0; // 指针归  0
      LED2 = 0; // 关发送指示
    }
  }
}

/****************************************************************
串口接收一个字符 :  一旦有数据从串口传至  CC2530,  则进入中断,将接收
到的数据赋值给变量  temp.
****************************************************************/
#pragma vector = URX0_VECTOR
__interrupt void UART0_ISR(void)
{
  URX0IF = 0; //  清中断标志
  temp = U0DBUF;
}

2016-01-03 11:12:13 aorangezzz 阅读数 1334
  • 串口通信和RS485-第1季第13部分

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

    6005 人正在学习 去看看 朱有鹏
/***********************************************************************************
*	标题:                  RS232串口通信试验                                        *          
*	功能:串口接收数据后打印,按回车键处理命令,通过数组储存命令				    *
*	      按 退格键 会准确地删除一位数据并清除串口的显示,尝试使用串口命令来清屏    *
*************************************************************************************/

#include <REG52.H>

sbit BEEP = P1^4;
sbit JDQ1 = P1^1;
sbit JDQ2 = P1^2;

bit Flag;
bit Flag_comm;
unsigned char ReData[5],SenData[5];	//接收数据缓存,发送数据缓存	,不指定大小会waring,应该是怕溢出
unsigned char serial_receive[64];   //接收命令的数组

static unsigned char coun = 0;

void serial_print(char *str){
	unsigned char i = 0;
	while(str[i] != '\0')
	{
		 SBUF = str[i];
		 while(!TI);
		 TI = 0;
		 i++;
	}
}

//串口初始化,初始化函数需要改进,修改为自动计算配置
void serial_init(){
	SCON = 0x50;      //REN=1允许串行接受状态,串口工作模式1    	       	   
	TMOD|= 0x20;      //定时器工作方式2                    
	PCON|= 0x80;                                                          
	TH1  = 0xFD;     //baud*2  /* reload value 19200、数据位8、停止位1。效验位无 (11.0592) 
	//	TH1 = 0xF3;					// //baud*2  /*  波特率4800、数据位8、停止位1。效验位无 (12M)
	TL1 = 0xF3;         
	TR1  = 1;                                                          
}

//主函数,串口接收完整指令后解析执行命令
void main (void) {
	serial_init();    //串口初始化要加入配置                                                     
	ES   = 1;        //开串口中断                  
	EA   = 1;        // 开总中断 

	serial_print("\n\rserial_init,waiting for input:\n\r");
	serial_print("common  input:");
	while(1)
    { 
		if(Flag_comm == 1){
			serial_print("\n\r");
			serial_print("receive common:");
			serial_print(serial_receive);
			serial_print("\n\r");
			//这里将传入参数进行命令解析
			//solve(serial_receive);
			serial_print("excuseing !!!!!!!!!!!!\n\r");
			serial_print("common  input:");
			coun = 0;   //打印后清零串口计数 
			Flag_comm = 0;	//处理命令后清除标志位
		}
 	}
}

/****************************************************
               串口中断程序
******************************************************/
void serial_interrupt (void) interrupt 4 using 1
{
	if(RI == 1)        //RI接受中断标志
	{
	 	RI = 0;		    //清除RI接受中断标志
		Flag=1;		    //接收到数据
		*ReData = SBUF;  //SUBF接受/发送缓冲器
		*SenData = *ReData;
		if( *ReData != 0x0d ){	   //等待接收回车
			if( *ReData == 0x08 ){	 //退格键
				serial_receive[--coun] = '\0';//遇到退格键要把刚刚的值清0,所以是--coun
				serial_print("\b ");               //覆盖掉原来的值
			}else{
				serial_receive[coun++] = *ReData;
			}
		}else{
			serial_receive[coun] = '\0';	 //遇到回车键,写\0,字符串终止
			Flag_comm = 1;					 //接收命令完成,解析命令
		}
	}
	if(Flag == 1){		 //接收到字符就打印,避免存在输入过快无法显示
		serial_print(SenData);
		Flag = 0;	
	}
}
//0x0d = \r 0x0a = \n	0x08 = \b


2016-04-15 17:02:17 CB_869145753_hp 阅读数 30426
  • 串口通信和RS485-第1季第13部分

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

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

在51单片机中,我们使用上下位机时,我们通常会发送一串字符串,将它作为信号发给单片机处理。

因为串口通信时,发送信息是以一个个字符的形式发送过来的,所以接收的就是一个个字符,通常我们是一个字符数组保存,在进行下一步处理,同时字符数组长度固定有限,但是如果上位机发送的字符不满足我们想要处理的数据时,其接收的数据多出的部分就有可能保存在SBUF中, 影响接下来的数据接收,以至于接下来的数据不满足我们的要求。或是发送数据少于数组长度时,也会出错。

在这里我的解决办法(以下以STC12C5A60S2芯片为例):

void serial_port_one_init()
{                       //根据自己单片机设置;

    //22.1184M   波特率: 115200
    SCON = 0x50; 
    BRT = 0xFA;
    AUXR |= 0x04;
    AUXR |= 0x01;
    AUXR |= 0x10;
   ES      =   1;    
   EA      =   1;    
}                   

#define Data_SIZE 10 //数据长度   9位数据 +  /r/n  -  /n =10位

char RevBuf[Data_SIZE];      //数据接收缓冲区
char temp[Data_SIZE];        //防数据抵消缓冲区
unsigned char flished_flag=0; //数据接收符合要求标志
int data_count=0;    //数据长度
int temp_length;    //数据长度
int data_flished_count = 0;  //
char data_flished;           //

void UART_one_Interrupt_Receive(void) interrupt 4
{  
    uchar temp;
  if(RI==1)
    {
        RI=0;
        temp=SBUF;
//        senduart(temp);  //用来测试过数据接收是否正确
        
        if(temp!='\n') //判断是否接收到结束符
        {
            RevBuf[data_count]=temp;// 否,就存到RevBuf【】数组中
            data_count++;
        }
        else
        {
            temp_length=data_count;//是,记录其数据长度
            data_count=0;
        }
        
    }
    
}             


void main(void)

{

    serial_port_one_init();  //串口初始化

   while(1)

    {

          if(Data_SIZE == temp_length)   //判断数据长度是否满足我们的要求。
        {
            for(i=0;i<Wifi_Data_SIZE;i++)
            {
                temp[i]=RevBuf[i];             // 同时我们将temp【】作为缓冲区,防止数据被冲到
            }
            flished_flag=1;          //数据接收成功标志
        }

      if(1==flished_flag)  //     数据接收完整成功
        {
            
            wifi_flished_flag=0;  //

           //

           //你想要实现的功能

/*

switch(temp[1]) //我常把数据第一位或前几位作为指令,后几位作为数据,你也可以把整个发送的数据就作为指令。

{

case 'A' :

//具体操作

break;

}

         */

        }

    }

  while(1);

}

同时某些特殊情况,我们会将数据写成:数据头+数据  

分析数据头,实现其代表的功能

上位机中 要在发送数据的最后加上 ‘/n’这个字符

用串口工具测试时, 发送数据为:数据+enter键(其代表的是两个字符 /r /n)



2019-11-23 10:17:48 ShenZhen_zixian 阅读数 595
  • 串口通信和RS485-第1季第13部分

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

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

单片机串口接收的几种常用的数据处理方法

一、为什么串口接收的数据需要处理
我们在做项目的时候经常会用到串口,当我们用串口和别的设备通讯的时候就需要严格遵循通讯协议,然而,仅仅是遵循通讯协议是不够的,因为单片机串口受到别的信号干扰的时候,容易出现数据错误,特别是串口发送的第一个字节和最后一个字节。一旦出现这种情况,设备之间的通讯可能会受到影响,甚至会导致系统瘫痪。另外,串口收到数据的时候,我们也需要判断一帧数据的长度,特别是指令发送比较频繁的时候。因此,串口在接收到数据之后应该先进行数据处理,再执行命令,这样能够增强产品的稳定性。

二、串口接收重点关注的几个标志
为了保证通讯的稳定性,一般的通讯协议会加入帧头、帧尾、数据长度、校验这四个标志中的一个或多个。它们的作用如下:
1、帧头:串口发送数据的第一个字节是最容易出错的,如果你把重要的指令放在第一个字节,一旦出现错误,可能会使从机执行错误的操作。而帧头能够有效规避这个问题。
2、帧尾:和帧头类似,帧尾也能避免最后一个字节出错,同时,它也可以作为接收端接收完成的标志。
3、数据长度:它可以作为接收端接收完成的标志。有时也能作为判断数据是否正确的标志。
4、校验:能够有效避免校验以外的所有数据的错误,但是校验正确不代表数据一定没有出错,每种校验方式都有一定的缺陷。
帧头、帧尾、数据长度和校验,这四种标志加起来之后能够大大的增强数据传输的稳定性,但不是每个通讯协议都会包含以上四个标志,可能只会用到其中的一两个。因为如果要发送的主要数据本身就比较长,加上这个几个标志之后会更长,这对于那种传输速度慢、传输数据时间长、传输指令频繁处理速度慢的设备来说,较长的指令可能会影响工作效率。具体我就不多说了,我今天主要讲的是接收数据的处理方法,大家根据自己的协议选择合适的处理方法就行了。

三、常用的几种数据处理方法
1、判断帧头:串口接收到第一个数据之后先判断是否是帧头,如果帧头正确就存起来继续收,反之则丢掉继续等帧头。示例代码片段如下:

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断
{
	Res = USART_ReceiveData(USART1);//读取接收到的数据,同时也清除了中断标志位
		   
	USART_RX_BUF[USART_RX_STA ++] = Res;
	if(USART_RX_BUF[0] != 0xA5 && USART_RX_STA == 1)
	{//帧头错误
	     USART_RX_STA = 0;//重新接收
	}
	if(USART_RX_STA >= USART_RX_Len)
	{//接收完成
	    USART_RX_STA = 0;
	    USART_RXHANDLE_FLAG = 1;
	}
}

这种处理方法能够有效避免第一个字节出错的问题,我就试过一次主设备那边传过来的数据帧头前面多了一个字节(可能是刚开始传输的时候电压不稳定产生的纹波),用这种方法就能够之间把第一个错误的数据丢掉,从正确的帧头开始接收。但是这种方法不能够检查帧头后面的数据是否正确。
2、判断帧尾:可以把帧尾作为一帧数据接收完成的标志。另外,当接收缓存存了多个指令的时候,帧尾能够帮助我们在一堆数据中区分出哪些数据是同一个指令的。当然,如果仅仅是区分数据用帧头也可以。不过这种办法必须保证帧尾和其他数据不一样,不然就会出现错误的判断。所以有些人为了避免这个问题会用两个字节作为帧尾,不过这样一来,数据长度就更大了,影响通讯效率。
3、根据数据长度判断是否完成接收:可以通过数据长度判断接收是否完成。如果协议里面的指令长度不是统一的,我们就不能根据固定的长度来接收数据。这个时候在一帧数据里面加入数据长度这个标志,就能够给单片机一个判断的准则,单片机接收到数据长度这个标志之后,根据这个长度来接收剩下的数据。示例代码片段如下:

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断
{
	Res = USART_ReceiveData(USART1);//读取接收到的数据,同时也清除了中断标志位
		   
	USART_RX_BUF[USART_RX_STA ++] = Res;
	if(USART_RX_BUF[0] != 0xA5 && USART_RX_STA == 1)
	{//帧头错误
	     USART_RX_STA = 0;//重新接收
	}
	If(USART_RX_STA == 4)
	{
	USART_RX_Len = USART_RX_BUF[3];//数据长度
	}
	if(USART_RX_STA >= (USART_RX_Len + 4))
	{//接收完成
	    USART_RX_STA = 0;
	    USART_RXHANDLE_FLAG = 1;
	}
}

4、根据接收时间判断一帧数据的长度。根据波特率计算出两个字节传输的时间间隔,接收到数据之后定时器开始计时,在定时器中断触发之前收到数据就清空,重新计时,超过两个字节的间隔时间,就认为是一帧数据接收完成。具体的程序我就不写了,这个网上能找到很多例程。这种方法适合接收长度不定的情况,在这个方法的基础上还可以加上帧头帧尾等标志,增强稳定性。
5、校验处理:校验一般是在接收完成之后进行,校验是很必要的,因为它包含一帧数据的所有字节,通过校验能够大大的减少出错的概率。

四、总结
其实串口接收数据处理主要要注意两点,第一点是单片机如何确定一帧数据接收完成,第二点是单片机如果判断接收到的数据是正确的指令。第一点可以通过帧尾,数据长度等标志确定接收完成。第二点可以先通过帧头初步判断指令的正确性,再通过校验二次处理,判断指令是否正确接收。

关于串口接收数据处理的相关内容就介绍到这里,如果还有什么问题,可以留言,如果文章有哪里写的不对,欢迎指正,谢谢!

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);
  完成上述配置之后,单片机就会有串口打印了

单片机串口通信

阅读数 528

单片机 串口通信

博文 来自: khbird
没有更多推荐了,返回首页