精华内容
下载资源
问答
  • matlab 串口接收数据 通过设置串口同时接收数据,结合上面的发送数据就可以编写 串口程序 时候 16进制发送 控制
  • 本文介绍串口USART收发数据处理方式总结的知识,很不错的知识,一起来看下吧。
  • c#com串口开发 可用串口读取 串口数据接收 串口数据发送
  • 2串口收发数据

    2017-09-25 09:05:51
    串口数据通信,数据收发串口接收数据处理

    一,精简版串口代码

    1,界面设计

    2,串口头文件

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    
    #include <QMainWindow>
    #include "win_qextserialport.h"
    #include "qextserialbase.h"
    #include "qextserialport.h"
    //我的修改123456789
    
    
    namespace Ui {
    class MainWindow;
    }
    
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    
    private:
        Ui::MainWindow *ui;
    
    
    //串口编程函数
    private:
        Win_QextSerialPort *myCom;
    private slots:
        //读取数据槽函数
        void readMyCom();
        void on_openMyComBtn_clicked();
        void on_closeMyConBtn_clicked();
        void on_sendMsgBtn_clicked();
    };
    
    
    #endif // MAINWINDOW_H
    
    

    3,串口.cpp文件

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QByteArray>
    #include <QString>
    
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
    
        ui->closeMyConBtn->setEnabled(false); //开始“关闭串口”按钮不可用
        ui->sendMsgBtn->setEnabled(false); //开始“发送数据”按钮不可用
        /*
        struct PortSettings myComSetting = {BAUD4800,DATA_8,PAR_NONE,STOP_1,FLOW_OFF,
        500};
        //定义一个结构体,用来存放串口各个参数
        myCom = new Win_QextSerialPort("com5",myComSetting,QextSerialBase::EventDriven);
        //定义串口对象,并传递参数,在构造函数里对其进行初始化
        myCom ->open(QIODevice::ReadWrite);
        //以可读写方式打开串口
        connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom()));
        //信号和槽函数关联,当串口缓冲区有数据时,进行读串口操作
        */
    }
    
    
    
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    
    //在下面添加 readMyCom()函数的定义,添加如下代码。
    void MainWindow::readMyCom() //读串口函数
    {
    QByteArray temp = myCom->readAll();
    //读取串口缓冲区的所有数据给临时变量 temp
    ui->textBrowser->insertPlainText(temp);
    //将串口的数据显示在窗口的文本浏览器中
    }
    
    
    
    
    //打开串口函数
    void MainWindow::on_openMyComBtn_clicked()
    {
        //打开串口之前的参数设置
        QString portName = ui->portName->currentText(); //获取串口名
        myCom = new Win_QextSerialPort(portName,QextSerialBase::EventDriven);
        //定义串口对象,并传递参数,在构造函数里对其进行初始化
        myCom ->open(QIODevice::ReadWrite); //打开串口
        if(ui->baudRate->currentText()==tr("4800")) //根据组合框内容对串口进行设置
        myCom->setBaudRate(BAUD4800);
        else if(ui->baudRate->currentText()==tr("9600"))
        myCom->setBaudRate(BAUD9600);
        else if(ui->baudRate->currentText()==tr("115200"))
        myCom->setBaudRate(BAUD115200);
        //设置波特率
        if(ui->dataBits->currentText()==tr("8"))
        myCom->setDataBits(DATA_8);
        else if(ui->dataBits->currentText()==tr("7"))
        myCom->setDataBits(DATA_7);
        //设置数据位
        if(ui->parityCombox->currentText()==tr("无"))
        myCom->setParity(PAR_NONE);
        else if(ui->parityCombox->currentText()==tr("奇"))
        myCom->setParity(PAR_ODD);
        else if(ui->parityCombox->currentText()==tr("偶"))
        myCom->setParity(PAR_EVEN);
        //设置奇偶校验
        if(ui->stopBits->currentText()==tr("1"))
        myCom->setStopBits(STOP_1);
        else if(ui->stopBits->currentText()==tr("2"))
        myCom->setStopBits(STOP_2);
        //设置停止位
        myCom->setFlowControl(FLOW_OFF); //设置数据流控制,我们使用无数据流控制的默认设置
        myCom->setTimeout(500); //设置延时
        connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom()));
        //信号和槽函数关联,当串口缓冲区有数据时,进行读串口操作
        ui->openMyComBtn->setEnabled(false); //打开串口后“打开串口”按钮不可
        ui->closeMyConBtn->setEnabled(true); //打开串口后“关闭串口”按钮可用
        ui->sendMsgBtn->setEnabled(true); //打开串口后“发送数据”按钮可用
        ui->baudRate->setEnabled(false); //设置各个组合框不可用
        ui->dataBits->setEnabled(false);
        ui->parityCombox->setEnabled(false);
        ui->stopBits->setEnabled(false);
        ui->portName->setEnabled(false);
        /*
        //定义一个结构体,用来存放串口各个参数
        struct PortSettings myComSetting = {BAUD4800,DATA_8,PAR_NONE,STOP_1,FLOW_OFF,
        500};
        //定义串口对象,并传递参数,在构造函数里对其进行初始化
        myCom = new Win_QextSerialPort("com5",myComSetting,QextSerialBase::EventDriven);
        //以可读写方式打开串口
        myCom ->open(QIODevice::ReadWrite);
    
    
        //信号和槽函数关联,当串口缓冲区有数据时,进行读串口操作
        connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom()));
        ui->openMyComBtn->setEnabled(false); //打开串口后“打开串口”按钮不可用
        ui->closeMyConBtn->setEnabled(true); //打开串口后“关闭串口”按钮可用
        ui->sendMsgBtn->setEnabled(true); //打开串口后“发送数据”按钮可用
        */
    
    
    }
    
    
    //关闭串口的函数
    void MainWindow::on_closeMyConBtn_clicked()
    {
       myCom->close();  //关闭串口函数
       ui->closeMyConBtn->setEnabled(false);  //关闭串口按钮失能
       ui->sendMsgBtn->setEnabled(false);  //发送按钮失能
       ui->openMyComBtn->setEnabled(true);  //打开按钮串口使能
    }
    
    
    //发送数据的槽函数
    void MainWindow::on_sendMsgBtn_clicked()
    {
        myCom->write(ui->sendMesLineEdit->text().toLocal8Bit());
    }
    4,文件工程目录
    
    
    

    运行环境;window7,Qt Creator5.4

    //上述代码为整个串口收发的核心代码,是最初的雏形,是所有后续的关键;

    既然是雏形,必然存在一定的缺陷:串口的收是全双工的,每发送一个数据,就会就收一个数据,从而会导致数据的断层,数据的显示不完整。

    针对上述问题做出如下改进

    二:串口收发数据的改进版

    改进方案:

    1、打开一个定时器,当串口接收到数据后,启动定时器,开始计时,计时时间到后,再对数据的进行处理;

    2、在定时器计时的这段时间内,对串口接收的数据进行追加到字符串的末尾;

    3、计时的时间到后,对数据进行按字节处理,这样就可以得到我们想要的数据啦。

    详情请阅如下代码:

    1,串口接收数据,将数据进行追加

    //在下面添加 readMyCom()函数的定义,添加如下代码。
    void mySerial::readMyCom() //读串口函数
    {
        timer.start(100);  //定时100ms处理数据
        myRecvData.append(myCom->readAll()); //将串口的数据保存起来
    }
    2,超时数据处理,
    //定时器超时处理函数
    void mySerial::timeoutSlot()
    {
        timer.stop(); //停止定时器
        int i=0;
        //**********重点在此*******//
        myRecvData.toHex();; //将读到的数据转化成16进制数据
        QDataStream out(&myRecvData,QIODevice::ReadWrite);//有字节数据发送过来
        while(!out.atEnd())
        {
            qint8 outChar = 0;//设置发送长度初始值为0
            out>>outChar;//每字节填充一次,直到结束
            recvData[i++]=outChar;
            if(i>99)
                break;
            qDebug()<<"timeoutSlot():"<<outChar;
        }
        emit getSerialReadData(recvData,i);
    }

    上述工程在Qt5.4中编译运行通过,完整工程如下:
    Qt串口通信两个完整工程
    博文索引  持续更新中。。。
    

    展开全文
  • 串口通信:串口收发数据,将接收到的数据写入数据库
  • Proteus仿真串口收发数据,不用一次一次的按开发板电源开关了
  • Qt界面,主要功能有1:串口收发数据 2:Qt实时显示串口接收数据
  • FPGA的GTP高速串行接口数据收发

    千次阅读 2018-10-25 23:20:30
    GTP(吉比特收发器)简称Gigabit Transceiver with Low Power,经常应用于板级通信,板与板,应用在高速串行接口数据收发。在A7系列芯片中我们叫GTP、在K7系列我们叫GTX、V系列叫GTH、对于不同速度等级的高速通信...

    GTP(吉比特收发器)简称Gigabit Transceiver with Low Power,经常应用于板级通信,板与板,应用在高速串行接口的数据收发。在A7系列芯片中我们叫GTP、在K7系列我们叫GTX、V系列叫GTH、对于不同速度等级的高速通信的物理接口。

    首先就是要了解aurora IP帧模式

    Aurora 协议是由Xilinx 公司提供的一个开放、免费的链路层协议,可以用来进行点到点的串行数据传输,具有实现高性能数据传输系统的高效率和简单易用的特点。Aurora 8b10协议是一个可扩展的、轻量级的链路层协议,可以用于单路或者多路串行数据通信

    1. AuroraIP帧模式                                                          

    1.1 IP核配置                                                                 

        Lane width Byte=4Bytes设置了用户AXI-Stream接口位宽是32bit 

        Lane Rate=5.0Gbps设置了高速串行总线的数据速率 

        GT Refclk=125Mhz 设置了高速串行总线参考时钟频率,需要参考板卡实际连接的晶振频率 

        Init clk=50Mhz用于初始化和产生复位的信号,请使用独立的时钟不要使用本IP核生成的用户时钟。 

        Drp clk=50Mhz 用于DRP配置的时钟,此时钟可以与Init clk 一致。 

        DataFlow Mode=Duplex 通信模式选择全双工,也可以选择单收或单发. 

        Interface =Frame用户接口模式选择帧模式,帧模式帧内部含有起始字节和结束字节,选择性使能CRC 

       用于数据校验,相对比流模式效率降低,但是能感知帧内是否出错。 

        Flow Control = UFC流控信号选择User Flow Control,加入流控机制,流控信息可以更优先的传送, 

       只有在Frame模式下可以选择。 

        Error Detection = CRC使能CRC校验帧数据是否出错。 

        GT Selection -> Lanes = 1;RefClk=GTPQ0选择高速接口数量和参考时钟,这部分设置芯片有专用管 

       脚对应,根据实际板卡和芯片型号选择。 

        Shared Logic = Include shared logic in core 共享逻辑资源不输出共享信号接口,只包含在IP核内 

       部,在共享模式下一些时钟PLL资源可以给多个核使用。 

        INITCLK = Single ended 初始化时钟选择单端时钟 

        未注明的设置选项保持默认即可 

    1.2 复位时序                                                             

    上电后GT_Reset和Reset同时复位,GT_Reset提前128clk退出复位,当LaneUp&ChannelUp出现下降沿后 

    触发复位时序,Reset提前进入复位,128个时钟后GT_Reset进入复位状态,GT_Reset保持128时钟周期后 

    退出复位,之后再经过128时钟周期Reset退出复位,复位顺序完成。

    1.3 用户流控信号   

    1.3.1 用户流控信号时序 

    用户流控信号可以插入数据流中,从而在接收端可以降低缓冲buffer压力,一般应用场景,当接收端 

    buffer即将溢出时,给发送端发送指令,使得发送端插入流控数据降低接收端数据量防止溢出。

    2. 帧模式结构框图      

                                                     

    tx_ctrl和rx_ctrl模块是用户设计模块。tx_ctrl产生 

    测试数据源,通过Aurora IP发送到传输介质中,接收端接收数据并检测CRC检测结果,并对CRC错包计 

    数。在调试期间可以用xilinx调试IP的VIO功能监测错包数量。

     

    展开全文
  • c#串口收发数据

    万次阅读 2015-10-15 17:02:31
    c#串口接收发送数据  重要的几个函数 构造函数 InitializeComponent(); //为串口绑定接收数据事件 this.serialPort1.DataReceived += new SerialDataReceivedEventHandler

    2015-11-20 15:10:09

    补充:串口要添加对应的空间

    //获取com口
    using System.IO.Ports;

    c#有串口控件

    设计界面如下:

     重要的几个函数

                构造函数
                InitializeComponent();
                //为串口绑定接收数据事件
                this.serialPort1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
                //初始化下拉串口名称列表框
                string[] ports = SerialPort.GetPortNames();
                Array.Sort(ports);
                dotlist.Add(100);
                /*
                串口设置
                this.serialPort1.PortNum=  comboBox1.Text.ToString(); //端口号
                this.serialPort1.Parity= 0; //奇偶校验
                this.serialPort1.BaudRate= 9600;//串口通信波特率
                this.serialPort1.ByteSize= 8; //数据位
                this.serialPort1.StopBits= 1;//停止位
                this.serialPort1.ReadTimeout= 1000; //读超时
                */
                comboBaudName.Items.AddRange(ports);
                //如果只有一个串口则选中
                if(comboBaudName.Items.Count==1) { comboBaudName.SelectedIndex = 0; }
            //默认波特率选9600
            this.comboBaudRate.Items.AddRange(new object[] {
                "2400",
                "4800",
                "9600",
                "19200",
                "38400",
                "57600",
                "115200"});
            if (ports.Length == 1) 
            { //comboBaudName.SelectedIndex = 0;  comboBaudRate.SelectedText = "9600"; }
            //打开或关闭串口
            private void button8_Click(object sender, EventArgs e)
            {
                //根据当前串口对象,来判断操作
                if(serialPort1.IsOpen)
                {
                    //串口状态是open时,text是关闭 点击,则关闭串口
                    serialPort1.Close();
                    button8.Text = "打开";
                }
                else
                {
                    //串口状态是close时,text是打开 点击,则设置好端口,波特率后打开
                    if(comboBaudName.Text=="")
                    {
                        MessageBox.Show("无效的串口!");
                        return;
                    }
                    if(comboBaudRate.Text=="")
                    {
                        MessageBox.Show("请设置波特率!");
                        return;
                    }
                    serialPort1.PortName = comboBaudName.Text;
                    serialPort1.BaudRate = int.Parse(comboBaudRate.Text);
                    try
                    {
                        serialPort1.Open();
                        button8.Text = "关闭";
                    }
                    catch(Exception e1)
                    {
                        //捕获到异常信息,创建一个新的comm对象,之前的不能用了。
                        serialPort1 = new SerialPort();
                        //显示异常信息给客户。
                        MessageBox.Show(e1.Message);
                    }
                    
                }
            }
            //接收串口数据函数
            private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
            {
                int n = serialPort1.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致
                byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
                received_count += n;//增加接收计数
                serialPort1.Read(buf, 0, n); ;//读取缓冲数据
                builder.Clear();//清除字符串构造器的内容
                //因为要访问ui资源,所以需要使用invoke方式同步ui。
                this.Invoke((EventHandler)(delegate
                {
                    //直接按ASCII规则转换成字符串
                    builder.Append(Encoding.ASCII.GetString(buf));
                    //追加的形式添加到文本框末端,并滚动到最后。
                    textBox1.AppendText(builder.ToString());
                }));
    
    
                SerialPort sp = (SerialPort)sender;
                string indata = sp.ReadExisting();
            }
            //发送串口数据
            private void SendStringData(string data)
            {
                if(serialPort1.IsOpen)
                {
                    serialPort1.Write(data);
                }
                else
                {
                    MessageBox.Show("串口没有打开");
                }
            }
            //发送数据按钮
            private void button10_Click(object sender, EventArgs e)
            {
                if(serialPort1.IsOpen)
                {
                    SendStringData(this.textBox2.Text);
                }
                
            }
    
    
    
    
    
    

    
    
    效果图:

    注意:串口号是程序打开时扫描的,这点不方便;只能是ASCII码,不然乱码。

    展开全文
  • 通过串口发送和接收数据
  • STM32串口发送数据接收数据方式总结

    万次阅读 多人点赞 2018-05-13 20:34:22
    之前写了篇关于ESP8266使用AT指令进行互相通讯的实验,在写STM32串口接发数据的程序中,觉得有必要将之前学的有关于串口方面的使用经历加以总结。 串口发送数据: 1. 串口发送数据最直接的方式就是标准调用...

     

           之前写了篇关于ESP8266使用AT指令进行互相通讯的实验,在写STM32串口接发数据的程序中,觉得有必要将之前学的有关于串口方面的使用经历加以总结。

     

    串口发送数据:

           1. 串口发送数据最直接的方式就是标准调用库函数  void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
    第一个参数是发送的串口号,第二个参数是要发送的数据了。但是用过的朋友应该觉得不好用,一次只能发送单个字符,所以我们有必要根据这个函数加以扩展。

    void Send_data(u8 *s)
    {
    	while(*s!='\0')
    	{ 
    		while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);	
    		USART_SendData(USART1,*s);
    		s++;
    	}
    }

            以上程序的形参就是我们调用该函数时要发送的字符串,这里通过循环调用USART_SendData来一 一发送我们的字符串。

    while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);

             这句话有必要加,他是用于检查串口是否发送完成的标志,如果不加这句话会发生数据丢失的情况。这个函数只能用于串口1发送。有些时候根据需要,要用到多个串口发送那么就还需要改进这个程序。如下: 

    void Send_data(USART_TypeDef * USARTx,u8 *s)
    {
    	while(*s!='\0')
    	{ 
    		while(USART_GetFlagStatus(USARTx,USART_FLAG_TC )==RESET);	
    		USART_SendData(USARTx,*s);
    		s++;
    	}
    }

            这样就可实现任意的串口发送。但有一点,我在使用实时操作系统的时候(如UCOS,Freertos等),需考虑函数重入的问题。当然也可以简单的实现把该函数复制一下,然后修改串口号也可以避免该问题。然而这个函数不能像printf那样传递多个参数,所以还可以在改进,最终程序如下

    void USART_printf ( USART_TypeDef * USARTx, char * Data, ... )
    {
    	const char *s;
    	int d;   
    	char buf[16];
    	
    	va_list ap;
    	va_start(ap, Data);
    
    	while ( * Data != 0 )     // 判断是否到达字符串结束符
    	{				                          
    		if ( * Data == 0x5c )  //'\'
    		{									  
    			switch ( *++Data )
    			{
    				case 'r':							          //回车符
    				USART_SendData(USARTx, 0x0d);
    				Data ++;
    				break;
    
    				case 'n':							          //换行符
    				USART_SendData(USARTx, 0x0a);	
    				Data ++;
    				break;
    
    				default:
    				Data ++;
    				break;
    			}			 
    		}
    		
    		else if ( * Data == '%')
    		{									  //
    			switch ( *++Data )
    			{				
    				case 's':										  //字符串
    				s = va_arg(ap, const char *);
    				
    				for ( ; *s; s++) 
    				{
    					USART_SendData(USARTx,*s);
    					while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
    				}
    				
    				Data++;
    				
    				break;
    
    				case 'd':			
    					//十进制
    				d = va_arg(ap, int);
    				
    				itoa(d, buf, 10);
    				
    				for (s = buf; *s; s++) 
    				{
    					USART_SendData(USARTx,*s);
    					while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
    				}
    				
    				Data++;
    				
    				break;
    				
    				default:
    				Data++;
    				
    				break;
    				
    			}		 
    		}
    		
    		else USART_SendData(USARTx, *Data++);
    		
    		while ( USART_GetFlagStatus ( USARTx, USART_FLAG_TXE ) == RESET );
    		
    	}
    }

            该函数就可以像printf使用可变参数,方便很多。通过观察函数但这个函数只支持了%d,%s的参数,想要支持更多,可以仿照printf的函数写法加以补充。
            2. 直接使用printf函数。        很多朋友都知道想要STM32要直接使用printf不行的。需要加上以下的重映射函数

           如果不想添加以上代码,也可以勾选以下的Use MicroLI选项来支持printf函数使用。

     

    串口接收数据:       

            串口接收最后应有一定的协议,如发送一帧数据应该有头标志或尾标志,也可两个标志都有。这样在处理数据时既能能保证数据的正确接收,也有利于接收完后我们处理数据。串口的配置在这里就不在赘述,这里我以串口2接收中断服务程序函数且接收的数据包含头尾标识为例。

    #define Max_BUFF_Len 18
    unsigned char Uart2_Buffer[Max_BUFF_Len];
    unsigned int Uart2_Rx=0;
    void USART2_IRQHandler() 
    {
    	if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生 
    	{
    		USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志
    			 
    		Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2);     //接收串口1数据到buff缓冲区
    		Uart2_Rx++; 
         		 
    		if(Uart2_Buffer[Uart2_Rx-1] == 0x0a || Uart2_Rx == Max_BUFF_Len)    //如果接收到尾标识是换行符(或者等于最大接受数就清空重新接收)
    		{
    			if(Uart2_Buffer[0] == '+')                      //检测到头标识是我们需要的 
    			{
    				printf("%s\r\n",Uart2_Buffer);        //这里我做打印数据处理
    				Uart2_Rx=0;                                   
    			} 
    			else
    			{
    				Uart2_Rx=0;                                   //不是我们需要的数据或者达到最大接收数则开始重新接收
    			}
    		}
    	}
    }

     


            数据的头标识为“\n”既换行符,尾标识为“+”。该函数将串口接收的数据存放在USART_Buffer数组中,然后先判断当前字符是不是尾标识,如果是说明接收完毕,然后再来判断头标识是不是“+”号,如果还是那么就是我们想要的数据,接下来就可以进行相应数据的处理了。但如果不是那么就让Usart2_Rx=0重新接收数据。这样做的有以下好处:

            1.可以接受不定长度的数据,最大接收长度可以通过Max_BUFF_Len来更改

            2.可以接受指定的数据

            3.防止接收的数据使数组越界
            这里我的把接受正确数据直接打印出来,也可以通过设置标识位,然后在主函数里面轮询再操作。

            

            以上的接收形式,是中断一次就接收一个字符,这在UCOS等实时内核系统中频繁的中断,非常消耗CPU资源,在有些时候我们需要接收大量数据时且波特率很高的情况下,长时间中断会带来一些额外的问题。所以以DMA形式配合串口的IDLE(空闲中断)来接受数据将会大大的提高CPU的利用率,减少系统资源的消耗。首先还是先看代码。

    #define DMA_USART1_RECEIVE_LEN 18
    void USART1_IRQHandler(void)                                 
    {     
        u32 temp = 0;  
        uint16_t i = 0;  
          
        if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)  
        {  
            USART1->SR;  
            USART1->DR; //这里我们通过先读SR(状态寄存器)和DR(数据寄存器)来清USART_IT_IDLE标志 			
            DMA_Cmd(DMA1_Channel5,DISABLE);  
            temp = DMA_USART1_RECEIVE_LEN - DMA_GetCurrDataCounter(DMA1_Channel5); //接收的字符串长度=设置的接收长度-剩余DMA缓存大小 
            for (i = 0;i < temp;i++)  
            {  
                Uart2_Buffer[i] = USART1_RECEIVE_DMABuffer[i];  
                    
            }  
            //设置传输数据长度  
            DMA_SetCurrDataCounter(DMA1_Channel5,DMA_USART1_RECEIVE_LEN);  
            //打开DMA  
            DMA_Cmd(DMA1_Channel5,ENABLE);  
        }        
    } 

            之前的串口中断是一个一个字符的接收,现在改为串口空闲中断,就是一帧数据过来才中断进入一次。而且接收的数据时候是DMA来搬运到我们指定的缓冲区(也就是程序中的USART1_RECEIVE_DMABuffer数组),是不占用CPU时间资源的。具体什么是IDLE中断和DMA需要朋友们先行了解。

        参考链接:

        https://blog.csdn.net/jdh99/article/details/8444474

        https://blog.csdn.net/phker/article/details/51925668   

       最后在讲下DMA的发送

    #define DMA_USART1_SEND_LEN 64
    void DMA_SEND_EN(void)
    {
    	DMA_Cmd(DMA1_Channel4, DISABLE);      
    	DMA_SetCurrDataCounter(DMA1_Channel4,DMA_USART1_SEND_LEN);   
    	DMA_Cmd(DMA1_Channel4, ENABLE);
    }

            这里需要注意下DMA_Cmd(DMA1_Channel4,DISABLE)函数需要在设置传输大小之前调用一下,否则不会重新启动DMA发送。

        有了以上的接收方式,对一般的串口数据处理是没有问题的了。下面再讲一下,在ucosiii中我使用信号量+消息队列+储存管理的形式来处理我们的串口数据。先来说一下这种方式对比其他方式的一些优缺点。一般对串口的处理形式是"生产者"和"消费者"的模式,即本次接收的数据要马上处理,否则当数据大量涌进的时候,就来不及"消费"掉生产者(串口接收中断)的数据,那么就会丢失本次的数据处理。所以使用队列就能够很方便的解决这个问题。

        在下面的程序中,对数据的处理是先接受,在处理,如果在处理的过程中,有串口中断接受数据,那么就把它依次放在队列中,队列的特征是先进先出,在串口中就是先处理先接受的数据,所以根据生产和消费的速度,定义不同大小的消息队列缓冲区就可以了。缺点就是太占用系统资源,一般51单片机是没可能了。下面是从我做的项目中截取过来的程序

    OS_MSG_SIZE  Usart1_Rx_cnt;          //字节大小计数值
    unsigned char Usart1_data;           //每次中断接收的数据
    unsigned char* Usart1_Rx_Ptr;        //储存管理分配内存的首地址的指针
    unsigned char* Usart1_Rx_Ptr1;       //储存首地址的指针
    void USART1_IRQHandler() 
    {
    	OS_ERR err;
    	OSIntEnter();
    	
      if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) != RESET) //中断产生 
      { 	 
        USART_ClearFlag(USART1, USART_FLAG_RXNE);     //清除中断标志
    		
        Usart1_data = USART_ReceiveData(USART1);     //接收串口1数据到buff缓冲区
    		
    		if(Usart1_data =='+')                     //接收到数据头标识
    		{
    //			OSSemPend((OS_SEM*		)&SEM_IAR_UART,  //这里请求信号量是为了保证分配的存储区,但一般来说不允许
    //			(OS_TICK		)0,                   //在终端服务函数中调用信号量请求但因为
    //			(OS_OPT			)OS_OPT_PEND_NON_BLOCKING,//我OPT参数设置为非阻塞,所以可以这么写
    //			(CPU_TS*		)0,
    //			(OS_ERR*		)&err); 
    //			if(err==OS_ERR_PEND_WOULD_BLOCK)	    //检测到当前信号量不可用
    //			{
    //				 printf("error");
    //			}				
    			Usart1_Rx_Ptr=(unsigned char*) OSMemGet((OS_MEM*)&UART1_MemPool,&err);//分配存储区
    			Usart1_Rx_Ptr1=Usart1_Rx_Ptr;		        //储存存储区的首地址
    		}
    		if(Usart1_data == 0x0a )   				//接收到尾标志
    		{                    
    			*Usart1_Rx_Ptr++=Usart1_data;
    			Usart1_Rx_cnt++;                        	//字节大小增加
    			OSTaskQPost((OS_TCB    *  )&Task1_TaskTCB,
                                       (void      *  )Usart1_Rx_Ptr1,    //发送存储区首地址到消息队列
                                       (OS_MSG_SIZE  )Usart1_Rx_cnt,
                                       (OS_OPT       )OS_OPT_POST_FIFO,  //先进先出,也可设置为后进先出,再有地方很有用
                                       (OS_ERR    *  )&err);
    									
    			Usart1_Rx_Ptr=NULL;          //将指针指向为空,防止修改
    			Usart1_Rx_cnt=0;	     //字节大小计数清零
    		}
    		else
    		{
    			*Usart1_Rx_Ptr=Usart1_data; //储存接收到的数据
    			Usart1_Rx_Ptr++;
    			Usart1_Rx_cnt++;
    		}	
    	}		 	
    	OSIntExit();
    }

           上面被注释掉的代码为我是为了防止当分区中没有空闲的存储块时加入信号量,打印出报警信息。当然我们也可以将存储块直接设置大一点,但是还是无法避免当没有可有存储块时会程序会崩溃现象。希望懂的朋友能告知下~。

            下面是串口数据处理任务,这里删去了其他代码,只把他打印出来了而已。

    void task1_task(void *p_arg)
    {
    	OS_ERR err;
    	OS_MSG_SIZE Usart1_Data_size;
    	u8 *p;
    	
    	while(1)
    	{
    		p=(u8*)OSTaskQPend((OS_TICK		)0, //请求消息队列,获得储存区首地址
    			(OS_OPT				)OS_OPT_PEND_BLOCKING,
    			(OS_MSG_SIZE*	)&Usart1_Data_size,
    			(CPU_TS*			)0,
    			(OS_ERR*			)&err);
    
    		printf("%s\r\n",p);        //打印数据
    
    		delay_ms(100);
    		OSMemPut((OS_MEM*	)&UART1_MemPool,    //释放储存区
    		(void*			)p,
    		(OS_ERR*		)&err);
    						 
    		OSSemPost((OS_SEM*	)&SEM_IAR_UART,    //释放信号量
    		(OS_OPT 	)OS_OPT_POST_NO_SCHED,
    		(OS_ERR*	)&err);
    						 
    		OSTimeDlyHMSM(0,0,1,500,OS_OPT_TIME_PERIODIC,&err);				 
    	}
    }

     

     

     

    展开全文
  • android串口收发数据

    2014-04-29 11:53:19
    android串口收发数据,GPS调试 工具,符合MB100麦哲伦主板
  • 以STM32为基础展示如何使用DMA收发串口数据 STM32F103 DMA收发 经过稳定测试 初始化后直接用
  • visual studio 2012 c# wpf 开发串口收发数据demo,仅供学习测试使用,已测,可正常收发数据
  • 之前在做项目的时候,串口接收数据要及时进行处理,虽然采用了自定义的串口协议,但是协议的包尾只有一个字节,经常判断不准数据是否接受完毕,所以就采用计时器+串口的方式来判定串口是否接受完成。 核心思想 ...
  • C++串口收发数据源码

    2012-03-02 16:51:13
    C++串口收发数据程序源码,具备收发功能。工具是VC++6.0开发的
  • Qt串口通信接收数据不完整的解决方法

    万次阅读 多人点赞 2016-03-17 16:38:17
    在使用串口接收数据时,当数据量大的时候会出现数据接收不完整的情况。因为串口数据获取函数readAll()由readyRead()信号触发,但readyRead()信号在串口读到起始标志时立即发送,并不保证一定是当前所发数据的起始...
  • 串口怎样传输数据

    千次阅读 多人点赞 2020-06-24 16:59:08
     串行接口简称为串口串行接口 (Serial Interface)是指数据一位一位地顺序传送。实现双向通信就需要一对传输线,即TX与RX线。 电路连接方式:  串口如果要实现双向传输,则设备1与设备2,TX与RX要交叉相连。 ...
  • 我做这个串口数据接收 dma+空闲中断 加fifo 实现串口的高效收发 ,主要是串口接收数据长度不定长,时间超时也不好做,还要串口收发的效率要高,采用串口数据接收 dma+空闲中断+fifo的方式 速度快和效率高,不...
  • C# SerialPort串口接收数据 数据不完整的解决方法
  • 这是一款用C#编写的串口调试助手,有16进制收发选择,而且有自动发送功能。收发数据分别存放在MYSQL数据库中,接受数据用工业控件iplotX绘制曲线。
  • QT串口延时接收数据

    千次阅读 2020-07-21 09:25:37
    遇到的问题:做了个串口小助手来接收数字湿度大气压力计,接收到的数据是分段的,不完整。 处理思路:创建两个槽函数(SLOT),当串口数据应答时系统会给一个 readyRead()信号,用槽函数接收一个信号,并处理。在...
  • STM32之串口DMA接收不定长数据

    万次阅读 多人点赞 2018-09-17 15:49:25
    STM32之串口DMA接收不定长数据 本文为杰杰原创,如需转载请说明出处 引言 在使用stm32或者其他单片机的时候,会经常使用到串口通讯,那么如何有效地接收数据呢?假如这段数据是不定长的有如何高效接收呢? ...
  • 使用C语言对串口发送来的数据进行接收,16进制显示数据,并保存到TXT中。
  • 模拟串口收发数据

    2020-03-10 11:02:44
    我们在进行上位机串口接收开发时,有时候需要绘制实时曲线,可以选择使用函数产生模拟数据,在实际工程中将数据改为读取实时设备的数据即可。(直接使用一个Qpoint模板的列表表示比较好) “串口数据接收进来之后先...
  • 串口收发数据CRC校验例程,VisualStudio工程
  • 低功耗BLE蓝牙串口收发数据
  • 为什么我用mfc写的上位机串口通讯程序每次打开只能接收一次数据,想要接收下一次的数据只能重新打开串口,小白求问大神们,用的是microsoft communications control 6.0控件。
  • 近日用串口终端通过ttl转ra232来收发嵌入式开发板的数据,打开串口终端的收发数据全为零,以为是自己开发板上数据线出现问题,经过测试,开发板完全正常,转接电路也正常。但是不管是接收还是发送数据依然出现是全零...
  • ZigBee串口收发数据

    千次阅读 2014-11-06 20:35:33
    ZigBee串口收发数据     本文转载自:http://blog.chinaunix.net/space.php?uid=20788636&do=blog&id=1841411  串口接收发送数据有两种方式,一种是中断的模式,另一种是DMA方式,这里...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 134,089
精华内容 53,635
关键字:

串口怎样接收数据