精华内容
下载资源
问答
  • linux串口收发数据不对(由于流控等设置不对导致)
    2021-05-14 01:14:02

    最近一个项目使用了嵌入式linxu串口通信,由于通信使用的是2进制数据,经常出现通信校验失败,数据帧大小没问题,就是校验出错

    c_iflag参数表

    键 值

    说 明

    IGNBRK

    忽略BREAK键输入

    BRKINT

    如果设置了IGNBRK,BREAK键输入将被忽略

    IGNPAR

    忽略奇偶校验错误

    PARMRK

    标识奇偶校验错误

    INPCK

    允许输入奇偶校验

    ISTRIP

    去除字符的第8个比特

    INLCR

    将输入的NL(换行)转换成CR(回车)

    IGNCR

    忽略输入的回车

    ICRNL

    将输入的回车转化成换行(如果IGNCR未设置的情况下)

    IUCLC

    将输入的大写字符转换成小写字符(非POSIX)

    IXON

    允许输出时对XON/XOFF流进行控制

    IXANY

    输入任何字符将重启停止的输出

    IXOFF

    允许输入时对XON/XOFF流进行控制

    IMAXBEL

    当输入队列满的时候开始响铃

    c_oflag:输出模式标志,控制终端输出方式,具体参数如表2所示。 表2 c_oflag参数

    键 值

    说 明

    OPOST

    处理后输出

    OLCUC

    将输入的小写字符转换成大写字符(非POSIX)

    ONLCR

    将输入的NL(换行)转换成CR(回车)及NL(换行)

    OCRNL

    将输入的CR(回车)转换成NL(换行)

    ONOCR

    第一行不输出回车符

    ONLRET

    不输出回车符

    OFILL

    发送填充字符以延迟终端输出

    OFDEL

    以ASCII码的DEL作为填充字符,如果未设置该参数,填充字符为NUL

    NLDLY

    换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s)

    CRDLY

    回车延迟,取值范围为:CR0、CR1、CR2和 CR3

    TABDLY

    水平制表符输出延迟,取值范围为:TAB0、TAB1、TAB2和TAB3

    BSDLY

    空格输出延迟,可以取BS0或BS1

    VTDLY

    垂直制表符输出延迟,可以取VT0或VT1

    FFDLY

    换页延迟,可以取FF0或FF1

    c_cflag:控制模式标志,指定终端硬件控制信息,具体参数如表3所示。 表3 c_cflag参数

    键 值

    说 明

    CBAUD

    波特率(4+1位)(非POSIX)

    CBAUDEX

    附加波特率(1位)(非POSIX)

    CSIZE

    字符长度,取值范围为CS5、CS6、CS7或CS8

    CSTOPB

    设置两个停止位

    CREAD

    使用接收器

    PARENB

    使用奇偶校验

    PARODD

    对输入使用奇偶校验,对输出使用偶校验

    HUPCL

    关闭设备时挂起

    CLOCAL

    忽略调制解调器线路状态

    CRTSCTS

    使用RTS/CTS流控制

    c_lflag:本地模式标志,控制终端编辑功能,具体参数如表4所示。 表4 c_lflag参数

    键 值

    说 明

    ISIG

    当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号

    ICANON

    使用标准输入模式

    XCASE

    在ICANON和XCASE同时设置的情况下,终端只使用大写。

    ECHO

    显示输入字符

    ECHOE

    如果ICANON同时设置,ERASE将删除输入的字符

    ECHOK

    如果ICANON同时设置,KILL将删除当前行

    ECHONL

    如果ICANON同时设置,即使ECHO没有设置依然显示换行符

    ECHOPRT

    如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)

    TOSTOP

    向后台输出发送SIGTTOU信号

    c_cc[NCCS]:控制字符,用于保存终端驱动程序中的特殊字符,如输入结束符等。c_cc中定义了如表5所示的控制字符。 表5 c_cc支持的控制字符

    说 明

    说 明

    VINTR

    Interrupt字符

    VEOL

    附加的End-of-file字符

    VQUIT

    Quit字符

    VTIME

    非规范模式读取时的超时时间

    VERASE

    Erase字符

    VSTOP

    Stop字符

    VKILL

    Kill字符

    VSTART

    Start字符

    VEOF

    End-of-file字符

    VSUSP

    Suspend字符

    VMIN

    非规范模式读取时的最小字符数

    tcsetattr函数用于设置终端的相关参数。参数fd为打开的终端文件描述符,参数optional_actions用于控制修改起作用的时间,而结构体termios_p中保存了要修改的参数。 optional_actions可以取如下的值: TCSANOW:不等数据传输完毕就立即改变属性。 TCSADRAIN:等待所有数据传输结束才改变属性。 TCSAFLUSH:清空输入输出缓冲区才改变属性。 错误信息: EBADF:非法的文件描述符。 EINTR:tcsetattr函数调用被信号中断。 EINVAL:参数optional_actions使用了非法值,或参数termios中使用了非法值。 ENCTTY:非终端的文件描述符。

    更多相关内容
  • 通过数码管将51单片机从电脑上接收来的数据进行转换并显示出来! 通过数码管将51单片机从电脑上接收来的数据进行转换并显示出来!
  • 这是一个我写的用C#实现串口通信的程序,可以扫描串口,然后选择串口,打开串口之后,如果打开成功,打开串口旁边的方框会变绿,这个可以验证是否成功打开,打开串口旁边还有关闭串口命令。 打开串口之后,在发送的...
  • C#对串口数据接收、发送的处理

    千次阅读 2021-10-14 15:45:33
    最近在做与设备进行串口通信交互的项目,然后简单记录一下过程 使用的winform应用程序 1.在工具箱拖拽SerialPort控件 引用串口命名控件 using System.IO.Ports; 2.先获取电脑所有串口列表 获取到列表后绑定给...

    最近在做与设备进行串口通信交互的项目,然后简单记录一下过程

    使用的winform应用程序

    方式1

    1.声明串口对象 或者直接在工具箱拖拽串口控件

    本篇文章不采用拖拽工具箱控件 直接声明对象
    声明串口对象

    SerialPort port = new SerialPort();//在选择了串口之后设置 串口、波特率、校验位等
    

    也可以直接拖拽工具箱的串口控件SerialPort
    在这里插入图片描述

    2.引用串口命名控件 声明串口对象、声明委托

    using System.IO.Ports;
    
    		SerialPort serialPort1 = new SerialPort();
            public delegate void Displaydelegate(byte[] InputBuf);
            public Displaydelegate disp_delegate;
            public Form1()
            {
                InitializeComponent();
    
                disp_delegate = new Displaydelegate(DispUI);
                serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
            }
    

    3.先获取电脑所有串口列表

    获取到列表后绑定给conboBox,以便选择串口打开 在load事件绑定下拉框

    String[] portnames = SerialPort.GetPortNames();
                foreach (var item in portnames)
                {
                    comboBox1.Items.Add(item);
                }
    

    4.实例化串口打开串口

    选择串口后实例化串口

    string aaa = comboBox1.SelectedItem.ToString();
    serialPort11 = new SerialPort(aaa, 9600, Parity.None, 8, StopBits.One); //初始化串口设置   serialPort11 声明为全局变量
    
                serialPort1.Open();
                if (serialPort1.IsOpen)
                {
                    MessageBox.Show("打开成功");
                }
                else
                {
                    MessageBox.Show("打开失败");
                }
    

    5.写一个接收数据事件获取串口发送来的数据

     //编写一个接收事件
            private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
               // writetxt("端口名称:" + serialPort1.PortName + "====" + "端口名称:" + "波特率:" + serialPort1.BaudRate + "串口状态:" + serialPort1.IsOpen + "错误信息:无");
                //string receive = "";//数据接收
                try
                {
                    Thread.Sleep(100);  //(毫秒)等待一定时间,确保数据的完整性 int len        
                    int len = serialPort1.BytesToRead;
                    if (len != 0)
                    {
                        byte[] buff = new byte[len];
                        serialPort1.Read(buff, 0, len);
                        //receive = Encoding.Default.GetString(buff);//数据接收内容
                        //textBox1.Text = receive + "\r\n"; //不能直接给textbox1 不然会报错
                        this.Invoke(disp_delegate, buff);
                    }
                }
                catch (Exception asd)
                {
                    //writetxt("端口名称:" + serialPort1.PortName + "====" + "端口名称:" + "波特率:" + serialPort1.BaudRate + "串口状态:" + serialPort1.IsOpen + "错误信息:" + asd.Message);
                    return;
                }
            }
    		public void DispUI(byte[] InputBuf)
            {
                //textBox1.Text = Convert.ToString(InputBuf);
                 
                string aaa = Encoding.Default.GetString(InputBuf);
                textBox1.Text = aaa;
               // writetxt("端口名称:" + serialPort1.PortName + "====" + "端口名称:" + "波特率:" + serialPort1.BaudRate + "串口状态:" + serialPort1.IsOpen + "错误信息:无     " + "数据:" + aaa);
    
            }
    

    6.模拟串口发送数据

    模拟串口调试工具可参考我另一篇文章链接https://blog.csdn.net/qq_39569480/article/details/120776868

    在这里插入图片描述

    方式2

    发送接收 完整代码示例

    源码下载地址demo

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.IO.Ports;
    using System.Threading;//线程申明
    
    namespace ck3
    {
        public partial class Form1 : Form
        {
            private void CheckPort()//检查串口是否可用
            {
                ckCheckBox.Items.Clear();//清除控件中的当前值
                bool havePort = false;
                string[] a = SerialPort.GetPortNames();
                if (a != null)
                {
                    
                    for (int i = 0; i < a.Length; i++)
                    {
                        bool use = false;
                        try
                        {
                            SerialPort t = new SerialPort(a[i]);
                            sp.Open();
                            sp.Close();
                            use = true;
                        }
                        catch
                        {
                        }
                        if (use)
                        {
                            ckCheckBox.Items.Add(a[i]);
                            havePort = true;
                        }
                    }
                }
                if (havePort)
                {
                    ckCheckBox.SelectedIndex = 0;//??
                }
                else
                {
                    MessageBox.Show("无可用串口...", "错误");
                }
    
            }
            private void SetPort()//设置串口
            {
                try
                {
                    sp.PortName = ckCheckBox.Text.Trim();//串口名给了串口类
                    sp.BaudRate = Convert.ToInt32(SendBox.Text.Trim());//Trim除去前后空格,讲文本转换为32位字符给予串口类
                    if (JywCheckBox.Text.Trim() == "奇校验")
                    {
                        sp.Parity = Parity.Odd;//将奇校验位给了sp的协议
                    }
                    else if (JywCheckBox.Text.Trim() == "偶校验")
                    {
                        sp.Parity = Parity.Even;
                    }
                    else
                    {
                        sp.Parity = Parity.None;
                    }
                    if (StopCheckBox.Text.Trim() == "1.5")
                    {
                        sp.StopBits = StopBits.OnePointFive;//设置停止位有几位
                    }
                    else if (StopCheckBox.Text.Trim() == "2")
                    {
                        sp.StopBits = StopBits.Two;
                    }
                    else
                    {
                        sp.StopBits = StopBits.One;
                    }
                    sp.DataBits = Convert.ToInt16(DataBox.Text.ToString().Trim());//数据位
                    sp.Encoding = Encoding.UTF8;//串口通信的编码格式
                    sp.Open();
                }
                catch { }
    
            }
            private string HexToASCII(string str)
            {
                try
                {
                    string[] mystr1 = str.Trim().Split(' ');
                    byte[] t = new byte[mystr1.Length];
                    for (int i = 0; i < t.Length; i++)
                    {
                        t[i] = Convert.ToByte(mystr1[i], 16);
                    }
                    return Encoding.UTF8.GetString(t);
    
                }
                catch (Exception ex)
                {
                    rbtReceicedAscii.Select();
                    MessageBox.Show("转换失败!" + ex.Message, "错误提示");
                    return str;
    
                }
            }
            private string ASCIIToHex(string my2)
            {
                try
                {
                    byte[] a = Encoding.UTF8.GetBytes(my2.Trim());
                    string mystr1 = "";
                    for (int i = 0; i < a.Length; i++)
                    {
                        mystr1 += a[i].ToString("X2") + " ";
                    }
                    return mystr1;
                }
                catch (Exception ex)
                {
                    rbtReceicedAscii.Select();
                    MessageBox.Show("转换失败!" + ex.Message, "错误提示");
                    return my2;
                }
    
    
            }
           
          
    
            private void Form1_Load(object sender, EventArgs e)
            {
                statusText.Text = "";//状态条初始化
                //设置窗口大小
                this.MaximizeBox = false;//隐藏最大化按钮
                this.MaximumSize = this.Size;//固定窗口尺寸最大为当前尺寸
                this.MinimumSize = this.Size;//固定窗口尺寸最小为当前尺寸
                BtlCheckBox.SelectedIndex = 5;
              //  JywCheckBox.Items.Clear();
                JywCheckBox.SelectedIndex = 1;
                StopCheckBox.SelectedIndex = 1;
               // DataBox.Items.Clear();
                DataBox.SelectedIndex = 1;
                statusText.Text = "";
                rbtSendAscii.Select();//默认选择ASCII字符显示
                rbtReceicedAscii.Select();//默认选择ASCII字符显示
    
            }
    
            private void btnChecked_Click(object sender, EventArgs e)
            {
                statusText.Text = "检测串口开始!";
                CheckPort();
                statusText.Text = "串口检测完成!";
            }
            private void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                Thread.Sleep(100);//等待
    
                this.Invoke((EventHandler)(delegate //异步委托一个线程
                {
                    try
                    {
                        byte[] a = new byte[sp.BytesToRead];//读出缓冲区串口通信的字节
                        sp.Read(a, 0, a.Length);//写入sp
                        string my2 = Encoding.UTF8.GetString(a);
                        string b = "";
                        if (rbtSendAscii.Checked)
                        {
                            b = ASCIIToHex(my2);
                        }
                        else
                        {
                            b = my2;
                        }
                        RecevieBox.Text += b + "\r\n";
                        statusText.Text = "接收成功!";
                    }
                    catch
                    {
                        statusText.Text = "接收失败!";
                    }
                }));
            }
            public Form1()
            {
                InitializeComponent();
            }
        
       
            //发送按钮
            private void button1_Click_1(object sender, EventArgs e)
            {
                try
                {
                    string mystr1 = SendBox.Text;
                    if (SixtyRe.Checked)//radio如果选择十六进制    则进行转换
                    {
                        mystr1 = HexToASCII(SendBox.Text);
                    }
                    byte[] a = Encoding.UTF8.GetBytes(mystr1);
                    string mystr2 = Encoding.UTF8.GetString(a);
                    sp.Write(mystr2);//将数据写入串行端口输出缓冲区
                    // tbxReceivedData.Text += tbxSendData.Text + "\r\n";
                    statusText.Text = "发送成功!";
                }
                catch
                {
                    statusText.Text = "发送失败";
                }
            }
    
            private void button1_Click_2(object sender, EventArgs e)
            {
                RecevieBox.Text = " ";
                SendBox.Text = " ";
            }
    
           
    
            private void BtnOpen_Click(object sender, EventArgs e)
            {
               
                    if (BtnOpen.Text == "打开串口")
                    {
                        SetPort();
                        if (sp.IsOpen)
                        {
                            statusText.Text = "串口" + ckCheckBox.Text + "已打开!";
                        }
                        else
                        {
                            try
                            {
                                sp.Open();
                                btnChecked.Enabled = false;
                                ckCheckBox.Enabled = false;
                                BtlCheckBox.Enabled = false;
                                JywCheckBox.Enabled = false;
                                StopCheckBox.Enabled = false;
                                DataBox.Enabled = false;
                                BtnOpen.Text = "关闭串口";
                                statusText.Text = "串口" + ckCheckBox.Text + "打开成功!";
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show("串口" + ckCheckBox.Text + "打开失败,失败原因:" + ex.Message, "错误提示");
                                statusText.Text = "串口" + ckCheckBox.Text + "打开失败,失败原因:" + ex.Message;
                            }
                        }
                    }
                    else //关闭串口
                    {
                        if (sp.IsOpen) //判断串口是否打开
                        {
                            try
                            {
                                sp.Close(); //关闭串口
                                            //启用设置控件
                            btnChecked.Enabled = true;
                            ckCheckBox.Enabled = true;
                            BtlCheckBox.Enabled = true;
                            JywCheckBox.Enabled = true;
                            StopCheckBox.Enabled = true;
                            DataBox.Enabled = true;
                            BtnOpen.Text = "打开串口";
                            statusText.Text = "串口" + ckCheckBox.Text + "关闭成功!";
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show("串口" + ckCheckBox.Text + "关闭失败,错误提示:" + ex.Message, "错误提示");
                            statusText.Text = "串口" + ckCheckBox.Text + "关闭失败,错误提示:" + ex.Message;
                            }
                        }
                        else
                        {
                        btnChecked.Enabled = true;
                        ckCheckBox.Enabled = true;
                        BtlCheckBox.Enabled = true;
                        JywCheckBox.Enabled = true;
                        StopCheckBox.Enabled = true;
                        DataBox.Enabled = true;
                        BtnOpen.Text = "打开串口";
                        statusText.Text = "串口未打开,无法关闭!";
                            MessageBox.Show("串口未打开,无法关闭!", "错误提示");
                        }
                    
    
                }
    
            }
    
           
            private void SixtySend_CheckedChanged(object sender, EventArgs e)
            {
                if (SixtyRe.Checked)//radio如果选择十六进制    则进行转换
                {
                    SendBox.Text = ASCIIToHex(SendBox.Text.ToString());
                }
            }
    
           
        }
    }
    
    
    展开全文
  • 串口读取的数据理论上无任何丢失。 imu信息是按照采用sensor_msgs/Imu+MagneticField的消息进行解析; alt信息是按照采用sensor_msgs/Imu的消息进行解析(自行解析); time帧数据是用来进行rtt时间同步的帧。
  • 关于串口数据接收处理有多种方法,下面主要总结两种: 1.引入接收状态标记USART_RX_STA //定义变量USART_RX_STA,接收状态 //bit15, 接收完成标志 //bit14, 接收到0x0d //bit13~0, 接收到的有效字节数目 /** * ...

    关于串口数据接收处理有多种方法,下面主要总结两种:

    1.引入接收状态标记USART_RX_STA

    
    int main(void)
    {
        u8 len;
        u16 times = 0;
    
        HAL_Init();
        SystemClock_Config();	//初始化系统时钟为80M
        delay_init(80); 		//初始化延时函数    80M系统时钟
        uart_init(115200);		//初始化串口,波特率为115200
    
        LED_Init();				//初始化LED
        KEY_Init();				//初始化KEY
    
        while(1)
        {
            if(USART_RX_STA & 0x8000)
            {
                len = USART_RX_STA & 0x3fff; //得到此次接收到的数据长度
                //printf("\r\n发送的消息为:\r\n");
                HAL_UART_Transmit(&UART1_Handler, (uint8_t*)USART_RX_BUF, len, 1000);	//发送接收到的数据
    
                while(__HAL_UART_GET_FLAG(&UART1_Handler, UART_FLAG_TC) != SET);		//等待发送结束
    
                printf("\r\n\r\n");//插入换行
                USART_RX_STA = 0;
            }
            else
            {
                times++;
    
                if(times % 5000 == 0)
                {
                    //printf("\r\nALIENTEK 潘多拉 STM32L475 IOT开发板 串口实验\r\n");
                    //printf("正点原子@ALIENTEK\r\n\r\n\r\n");
    				printf("%ld",times);
                }
                //if(times % 200 == 0)printf("请输入数据,以回车键结束\r\n");
                if(times % 30 == 0)LED_B_TogglePin; //闪烁LED,提示系统正在运行.
    
                delay_ms(10);
            }
        }
    }
    //定义变量USART_RX_STA,接收状态
    //bit15,	接收完成标志
    //bit14,	接收到0x0d
    //bit13~0,	接收到的有效字节数目
    
    /**
     * @brief	串口1中断服务程序
     *
     * @remark	下面代码直接把中断控制逻辑写在中断服务函数内部
     * 			说明:采用HAL库处理逻辑,效率不高。
     *
     * @param   void
     *
     * @return  void
     */
    void USART1_IRQHandler(void)
    {
        u8 Res;
    
        if((__HAL_UART_GET_FLAG(&UART1_Handler, UART_FLAG_RXNE) != RESET)) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
        {
            HAL_UART_Receive(&UART1_Handler, &Res, 1, 1000);
    
            if((USART_RX_STA & 0x8000) == 0) //接收未完成
            {
                if(USART_RX_STA & 0x4000) //接收到了0x0d
                {
                    if(Res != 0x0a)USART_RX_STA = 0; //接收错误,重新开始
    
                    else USART_RX_STA |= 0x8000;	//接收完成了
                }
                else //还没收到0X0D
                {
                    if(Res == 0x0d)USART_RX_STA |= 0x4000;
                    else
                    {
                        USART_RX_BUF[USART_RX_STA & 0X3FFF] = Res ;
                        USART_RX_STA++;
    
                        if(USART_RX_STA > (USART_REC_LEN - 1))USART_RX_STA = 0; //接收数据错误,重新开始接收 USART_REC_LEN为定义的最大接收字节数
                    }
                }
            }
        }
        HAL_UART_IRQHandler(&UART1_Handler);//处理串口中断请求
    }
    

    函数:HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint16_t *pData, uint16_t Size, uint32_t Timeout)
    大致流程:判断是否忙–>锁住–>标记接收忙–>获取tick计数–>赋值RxXferCount有多少数据要接收–>每次从DR内获取一个Byte存在pData指向的空间
    这个接收函数是阻塞式的。参数Timeout是超时时间,代表某次执行函数最多占用串口的时间,单位是毫秒。简单来说,在本次数据接收完之前,不能处理其他数据。所以,调用函数的时候要指明参数,本次接收占用多长时间,在此期间,串口资源被独占。如果在规定的时间内,数据接收完毕,那就释放占用的串口资源;如果到了时间,即便数据还没有接收完毕,(比如数据量很大),仍需要归还串口资源的控制权,供其他外设使用。

    /**
      * @brief Receive an amount of data in blocking mode.
      * @note When FIFO mode is enabled, the RXFNE flag is set as long as the RXFIFO
      *       is not empty. Read operations from the RDR register are performed when
      *       RXFNE flag is set. From hardware perspective, RXFNE flag and
      *       RXNE are mapped on the same bit-field.
      * @param huart   UART handle.
      * @param pData   Pointer to data buffer.
      * @param Size    Amount of data to be received.
      * @param Timeout Timeout duration.
      * @retval HAL status
      */
    HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
    {
      uint16_t *tmp;
      uint16_t uhMask;
      uint32_t tickstart = 0;
    
      /* Check that a Rx process is not already ongoing */
      if (huart->RxState == HAL_UART_STATE_READY)
      {
        if ((pData == NULL) || (Size == 0U))
        {
          return  HAL_ERROR;
        }
    
        /* Process Locked */
        __HAL_LOCK(huart);
    
        huart->ErrorCode = HAL_UART_ERROR_NONE;
        huart->RxState = HAL_UART_STATE_BUSY_RX;
    
        /* Init tickstart for timeout managment*/
        tickstart = HAL_GetTick();
    
        huart->RxXferSize  = Size;
        huart->RxXferCount = Size;
    
        /* Computation of UART mask to apply to RDR register */
        UART_MASK_COMPUTATION(huart);
        uhMask = huart->Mask;
    
        /* as long as data have to be received */
        while (huart->RxXferCount > 0U)
        {
          if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
          {
            return HAL_TIMEOUT;
          }
          if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
          {
            tmp = (uint16_t *) pData ;
            *tmp = (uint16_t)(huart->Instance->RDR & uhMask);
            pData += 2U;
          }
          else
          {
            *pData++ = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);
          }
          huart->RxXferCount--;
        }
    
        /* At end of Rx process, restore huart->RxState to Ready */
        huart->RxState = HAL_UART_STATE_READY;
    
        /* Process Unlocked */
        __HAL_UNLOCK(huart);
    
        return HAL_OK;
      }
      else
      {
        return HAL_BUSY;
      }
    }
    

    2.使用回调函数

    串口中断的执行过程:

    USART2_IRQHandler(void)      //启动文件中的中断向量,处理串口的总中断
    HAL_UART_IRQHandler(UART_HandleTypeDef *huart)    //处理具体某个串口中断请求
    UART_Receive_IT(UART_HandleTypeDef *huart)   //从数据寄存器读取一个字节数据存储在一个变量里,在接收完数据量为RxXferCount的数据后失能接收中断、赋值相应的标志位 接着执行回调函数
    HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
    

    首先在启动文件中找到中断向量,然后依次go to definition 就可以顺藤摸瓜捋清串口中断的执行步骤。
    接下来是回调函数的处理:

    /**
      * 函数功能: 串口接收完成回调函数
      * 输入参数: 无
      * 返 回 值: 无
      * 说    明:无
      */
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
    {
      HAL_UART_Transmit(&husartx,&aRxBuffer,3,0xffff);
      HAL_UART_Receive_IT(&husartx,&aRxBuffer,3);//再次使能串口接收中断
      //HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
      //用户定义一个缓存区,大小随意,然后通过该函数把这个缓存区对应到串口的接收,
      //上面函数的意思就是把aRxBuffer作为缓存区,
      //然后usart1接收数据的时候就放到aRxBuffer这个地址及其递增的地址中
      //当接收到3Bytes数据之后调用一次callback函数,(可以设置接收固定长度数据后进入回调函数处理)
      //并使能串口接收中断功能。
    }
    

    显然使用回调函数程序逻辑清晰、代码简洁易懂,执行效率较高。
    引用正点原子的流程图:
    在这里插入图片描述

    3.串口发送中断

    串口发送中断使用较少,这里简单补充说明。
    串口发送中断的过程大致如下:

    USART2_IRQHandler(void)      //启动文件中的中断向量,处理串口的总中断
    HAL_UART_IRQHandler(UART_HandleTypeDef *huart)    //处理具体某个串口中断请求
    UART_EndTransmit_IT(UART_HandleTypeDef *huart)    //发送完成中断,失能发送完成中断,之后调用回调函数
    HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);//发送完成后执行回调函数
    

    使能中断发送:发送指定长度的数据并使能发送中断

    HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
    
    展开全文
  • 之前在做项目的时候,串口接收数据要及时进行处理,虽然采用了自定义的串口协议,但是协议的包尾只有一个字节,经常判断不准数据是否接受完毕,所以就采用计时器+串口的方式来判定串口是否接受完成。 核心思想 ...
    使用背景:

    之前在做项目的时候,串口接收的数据要及时进行处理,虽然采用了自定义的串口协议,但是协议的包尾只有一个字节,经常判断不准数据是否接受完毕,所以就采用计时器+串口的方式来判定串口是否接受完成。

    核心思想

    根据波特率来计算接收一个字节所需要的时间,当超过这个时间没有收到数据,则表明这一帧数据已经接受完毕

    实现方法

    串口中断函数接收第一个字节之后,开启定时器计数。接受下一个字节的时候清空定时器计数。如此,当没有数据接收后,计时器无法清零,当计时器计数超过设定的数值之后,触发定时器溢出中断,此时数据即接收完毕

    Created with Raphaël 2.2.0 开始 定义 计时标志位、完成标志位 接收数据,清空计时标志位 开启定时器,计时标志位增加 串口未收到数据? 计时标志位增加,超过设定值 接收完成标志位置1,处理数据 结束 yes no

    下面是代码:

    • 1、为了方便,定义一个结构体,主要内容如下所示:
    typedef struct _UART_FLAG_STRUCT
    {
    	uint8_t UART1Flag;//数据接受完成标志
    	uint8_t UART1String[160];//最大长度,自定义
    	uint8_t UART1Counter;//收到的数据长度,计数作用
    	uint8_t usart1_start;//接收开始,定时器计时启动
    	uint8_t usart1_counter;//定时器计时次数
    }	UartFlagSt;
    
    UartFlagSt UartFlagStC;
    
    • 串口配置:
    /************************************************
    | 关键词 |USARTInit(u32 band)
    | - - - - - - - - - - - - - - - - - - - - - - - -
    |  入参  |u32 band,配置波特率
      - - - - - - - - - - - - - - - - - - - - - - - - 
    | 返回值 |None
      - - - - - - - - - - - - - - - - - - - - - - - -
    |  功能  |初始化串口1,使能中断
    **************************************************/
    void USARTInit(u32 band)
    {
    	GPIO_InitTypeDef  GPIO_InitStructure;
    	USART_InitTypeDef USART_InitStructure;
    	NVIC_InitTypeDef  NVIC_InitStructure;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO,ENABLE);
    	
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Pin  =GPIO_Pin_9;//send
    	GPIO_Init(GPIOA,&GPIO_InitStructure);
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//receive
    	GPIO_Init(GPIOA,&GPIO_InitStructure);
    	
    	USART_InitStructure.USART_BaudRate = band;
    	USART_InitStructure.USART_HardwareFlowControl = 0;
    	USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;
    	USART_InitStructure.USART_Parity = USART_Parity_No;
    	USART_InitStructure.USART_StopBits =USART_StopBits_1;
    	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    	USART_Init(USART1,&USART_InitStructure); //初始化串口1
    
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_Init(&NVIC_InitStructure);
    	
    	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启串口接受中断
    	USART_Cmd(USART1,ENABLE);                    //使能串口1 
    }
    
    /************************************************
    | 关键词 |UART1_SendString(uint8_t* str,uint8_t counter)
    | - - - - - - - - - - - - - - - - - - - - - - - -
    |  入参  |uint8_t* str    发送的数据
    |	|uint8_t counter 发送数据的长度
      - - - - - - - - - - - - - - - - - - - - - - - - 
    | 返回值 |无
      - - - - - - - - - - - - - - - - - - - - - - - -
    |  功能  |串口1发送函数
    **************************************************/
    void UART1_SendString(uint8_t* str,uint8_t counter)
    {
    	for(int i = 0;i<counter;i++)
    	{
    		USART_SendData(USART1,*str);
    		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
    		str++;
    	}
    }
    
    • 定时器配置:
    /************************************************
    | 关键词 |TIM2_Init(u16 arr,u16 psc)
    | - - - - - - - - - - - - - - - - - - - - - - - -
    |  入参  |u16 arr 周期,u16 psc 预分频
    | - - - - - - - - - - - - - - - - - - - - - - - - 
    | 返回值 |无
    | - - - - - - - - - - - - - - - - - - - - - - - -
    |  功能  |定时器初始化
    **************************************************/  
    void TIM2_Init(u16 arr,u16 psc)
    {
    	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    	
    	TIM_TimeBaseStructure.TIM_Period = arr; //	周期 72-1 max
    	TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频 
    	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
    	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 
    	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE );
    
    	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    	NVIC_Init(&NVIC_InitStructure);
    
    	TIM_Cmd(TIM2, ENABLE);
    }
    
    • 串口中断函数:
    /************************************************
    | 关键词 |USART1_IRQHandler
    | - - - - - - - - - - - - - - - - - - - - - - - -
    |  入参  |None
      - - - - - - - - - - - - - - - - - - - - - - - - 
    | 返回值 |None
      - - - - - - - - - - - - - - - - - - - - - - - -
    |  功能  |1、消除错误;
    |	|2、将数据接受至结构体中的数,
    |       |并启动UartFlagStC.usart1_start = 1;UartFlagStC
    |       |.usart1_counter = 0;定时/刷新功能。
    **************************************************/
    void USART1_IRQHandler(void)
    {
    /*****此段注释代码为消除各种串口错误,在串口环境很差的情况下可以直接将此段代码取消注释,基本可以保证串口代码正常工作******
    	if((USART_GetITStatus(USART1,USART_IT_ORE) == SET)||(USART_GetFlagStatus(USART1,USART_FLAG_ORE) == SET))
    	{
    		USART_ReceiveData(USART1);
    		USART_ClearITPendingBit(USART1,USART_IT_ORE);
    		USART_ClearFlag(USART1,USART_IT_ORE);
    	}
    	
    	if((USART_GetITStatus(USART1,USART_IT_NE) == SET)||USART_GetFlagStatus(USART1, USART_FLAG_NE) != RESET)
    	{
    		USART_ClearITPendingBit(USART1,USART_IT_NE);
    		USART_ClearFlag(USART1, USART_FLAG_NE);
    	}
    
    	if((USART_GetITStatus(USART1,USART_IT_FE) == SET)||USART_GetFlagStatus(USART1, USART_FLAG_FE) != RESET)
    	{
    		USART_ClearITPendingBit(USART1,USART_IT_FE);
    		USART_ClearFlag(USART1, USART_FLAG_FE);
    	}
    
    	if((USART_GetITStatus(USART1,USART_IT_PE) == SET)||USART_GetFlagStatus(USART1, USART_FLAG_PE) != RESET)
    	{
    		USART_ClearITPendingBit(USART1,USART_IT_PE);
    		USART_ClearFlag(USART1, USART_FLAG_PE);
    	}
    ****************************************************************************************************/
    	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    	{
    		if(UartFlagStC.UART1Counter<160)//设定的数组最大为160,要小于这个数,防止溢出
    		{
    			UartFlagStC.UART1String[UartFlagStC.UART1Counter] = USART_ReceiveData(USART1);//将数据存到数组里面
    			UartFlagStC.UART1Counter++;//收到的数据个数+1
    			UartFlagStC.usart1_start = 1;//定时器开始工作
    			UartFlagStC.usart1_counter = 0;//清空定时器计数
    		}else UartFlagStC.UART1Counter = 0;//如果接受的数据超过设定值,则清空接收值,防止数据溢出
    		USART_ClearITPendingBit(USART1,USART_IT_RXNE);
    	}
    }
    

    可以看到,当有数据进来的时候,UartFlagStC.UART1Counter不断自增,数据将会依次存入UartFlagStC.UART1String[]数组中。
    同时,UartFlagStC.usart1_start计时器开始计数标志位置一(让在定时器中断函数里面自增的UartFlagStC.usart1_counter得以正常增加),同时也将UartFlagStC.usart1_counter清零,以表示有数据接收,防止超过设定值,使得UartFlagStC.UART1Flag置一,错误的提示数据提前接收完成。

    • 定时器中断函数:
      在下面代码提示插入任务的地方插入我们想执行的任务/代码,即可正常使用
    /************************************************
    | 关键词 |TIM2_IRQHandler
    | - - - - - - - - - - - - - - - - - - - - - - - -
    |  入参  |无
    | - - - - - - - - - - - - - - - - - - - - - - - - 
    | 返回值 |无
    | - - - - - - - - - - - - - - - - - - - - - - - -
    |  功能  |定时器中断函数
    **************************************************/  
    void TIM2_IRQHandler(void)
    {
    	if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    	{
    		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    		/**********************/
    		 在此处插入执行的任务。
    		/**********************/
    	}
    }
    
    • 关键代码:
      这个代码是我们任务重最重要的部分,主要实现了我们上述流程图的计时/完成任务,之所以将这部分功能单独拆解写成一个函数的形式,主要是为了移植方便,并且在定时器多任务的时候让定时器中断函数看起来更整洁一点。
    使用方法:将此函数插入定时器中断函数。
    /************************************************
    | 关键词 |USART1InsetTimer
    | - - - - - - - - - - - - - - - - - - - - - - - -
    |  入参  |None
      - - - - - - - - - - - - - - - - - - - - - - - - 
    | 返回值 |无
      - - - - - - - - - - - - - - - - - - - - - - - -
    |  功能  |嵌入定时器中断函数中,串口数据接收完毕后
    |		 |立刻执行,适用于延时性小、数据量密的场景。
    **************************************************/
    void USART1InsetTimer(void)
    {
    	if(UartFlagStC.usart1_start == 1)//此标志位是在串口接收数据时候会置1
    	{
    		UartFlagStC.usart1_counter++;//定时器计数标志位
    		if(UartFlagStC.usart1_counter >USART_COUNTER_9600)//如果超过波特率为9600时一个字节的所需要的时间,时间计算方法下面有讲解
    		{
    			UartFlagStC.UART1Flag = 1;//接收完成标志位置1
    			UartFlagStC.usart1_counter = 0;//计数值清零
    			UartFlagStC.usart1_start = 0;//计数器启动标志位置0
    		}
    	}
    }
    

    在这里,当(UartFlagStC.usart1_start置一后,UartFlagStC.usart1_counter会不断自增(串口中断中会清零此计数位),而一旦超过设定值USART_COUNTER_9600,就会将接收完成标志位UartFlagStC.UART1Flag置一,同时清空定时器技术位UartFlagStC.usart1_counter,并清零计数允许标志位UartFlagStC.usart1_start

    • 处理数据:
      如果处理数据很快的话可以直接放在定时器中断函数里面执行,如果还有比较长的延时函数,或者在执行过程中花费时间太久则可以放入主函数循环中进行处理:
      老规矩,先进行封装一层:
    /************************************************
    | 关键词 |USART1Hanndle
    | - - - - - - - - - - - - - - - - - - - - - - - -
    |  入参  |None
      - - - - - - - - - - - - - - - - - - - - - - - - 
    | 返回值 |无
      - - - - - - - - - - - - - - - - - - - - - - - -
    |  功能  |串口1接收数据处理函数,任务若花费时间较长,
    |        |可放置于while()循环中,由定时器确定是否执行。
    **************************************************/
    void USART1Hanndle(void)
    {
    	if(!UartFlagStC.UART1Flag) return;
    	/*********执行任务*************/		
    	printf("%s\r\n",UartFlagStC.UART1String);
    	/****************************/
    	memset(UartFlagStC.UART1String,0,160);
    	UartFlagStC.UART1Counter = 0;
    	UartFlagStC.UART1Flag = 0;
    }
    

    主函数实现:

    /************************************************
    | 关键词 |main
    | - - - - - - - - - - - - - - - - - - - - - - - -
    |  入参  |None
    | - - - - - - - - - - - - - - - - - - - - - - - - 
    | 返回值 |无
    | - - - - - - - - - - - - - - - - - - - - - - - -
    |  功能  |主函数入口,配置文件,设置时钟,滴答定时器
    |        |周期,并开启看门狗
    **************************************************/  
    int main()
    {
    	SystemInit();   				 	//系统时钟72MHz
    	SysTick_Config(SystemCoreClock/1000);        /* SysTick 1 msec interrupts */
    	TIM2_Init(71,999);//1ms中断一次
    	USARTInit(9600);//波特率为9600
    	while(1)
    	{
    		USART1Hanndle();
    	}
    }
    

    流程/细节讲解

    • 不同波特率延时时间计算:

    可能会有人对void USART1InsetTimer(void)中的溢出时间USART_COUNTER_9600有疑问,不知道如何计算,计算方法如下:

    首先,1个字符串口包含起始位数据位校验位停止位,其中有些位长度可以自己设定,
    这里我们按一个字节传输有1+8+1+1共10位长度来计算。
    波特率表示的意思是在1sec内可以传输的位数


    接下来就是一元一次方程


    设1个字节所用时间为X,波特率为9600,则:

    ( 1 ∗ 10 ) / X = 9600 / 1000 ( m s ) (1 * 10) / X = 9600 / 1000(ms) (110)/X=9600/1000(ms)
    解得X ≈ 1.04167 ms = 2(X为整型,必须向上取整!)

    X代表的意思是一帧数据传输的时间,意思就是每过X单位时间,即有一个数据接受完毕,同时下一个数据也即将接受。
    USART_COUNTER_9600的数值设定为X1
    UartFlagStC.usart1_counter则只要在串口中断函数内清空,那么UartFlagStC.usart1_counter就不会超过X,
    那么也就不会将接受完成标志位UartFlagStC.UART1Flag置1;
    一旦没有数据继续接收,那么UartFlagStC.usart1_counter在中断函数里面将不断自增,直至超过X,此时接受完成标志位UartFlagStC.UART1Flag将会置1。
    同时,时间设定要根据波特率的不同要计算不同的数值。

    下载地址 :https://download.csdn.net/download/qq_31431301/12287318


    1. 实际使用过程中,一定要将USART_COUNTER_9600的设定值大于X,因为在此方法中,串口中断函数不仅要判断数据接收标志位,还有清零置一的操作,实际工作时间肯定要大于X!,一般取3~5倍X的时间。 ↩︎

    展开全文
  • QT QSerialPort 封装,阻塞方式发送数据等待读取缓冲区数据结果,使用QT信号量阻塞,线程中初始化串口和读取数据
  • 我有一个Python程序,它通过PySerial模块从串口读取数据.我需要记住的两个条件是:我不知道有多少数据会到达,我不知道何时需要数据.基于此,我提出了以下代码片段:#Code from main loop, spawning thread and waiting...
  • QT笔记:串口延时接收数据

    千次阅读 2020-12-30 22:51:51
    熟悉QT开发的朋友应该都知道,在开发QT串口应用程序的时,会遇到接收数据不完整的情况,这是因为串口是异步收发,而默认情况下QSerialPort没有对串口收进行阻塞,所以才会出现串口数据接收不完整的情况。解决办法很...
  • 2、串口自定义协议接收一串十六进制数据进行存储,并将其中的两个字节转化为十进制数据 3、串口助手发送字符控制LED的亮灭 4、发送一个字节函数 5、发送两个字节函数 6、重定向printf和getchar函数
  • 串口通信中接收数据时延迟处理与缓存处理的解决方案C利用串口进行通信当发送方A将数据写入串口后通过无线或有线方式将数据传送给接收方BB通过调用串口读方法comm.read参数即可将数据读出。原理十分简单但最近在利用...
  • 串口收发数据实验

    千次阅读 2018-11-15 18:26:40
     利用CC2530的串口0不停的打印信息到电脑上,同时接收串口发过来了的数据,把发送过来的数据直接送回给电脑。 二、实验环境  1.硬件:通用节点或任意传感器节点一个、USB仿真器、USB电缆、PC机;  2.软件:...
  • 之前在做电机测试的时候,由于数据接受不完整,便在将存储数据的语句放在的循环里,在100ms内只要串口数据就将数据缓存到内存中,解决了此问题。 while(globalPort.waitForReadyread(100)) buffer.append(global...
  • FPGA串口收发(三):接收数据,再转发出去 功能:测试串口接收数据,再将数据串口发出 // 模拟串口信号线,串行接收数据 1101_1000 ,转换为并行数据, 并显示 D8 // 把并行数据 D8 传给串口输出模块,串行输出...
  • 2.用串口助手向代码发送数据,并将发送过来的数据保存在数据库中,按数据和保存数据形式保存到数据库中。代码如下:import serial,pymysql,threading,timex=serial.Serial('com1',9600,timeout=1)def faSo...
  • 关于串口数据的发送和接收(调试必备)

    万次阅读 多人点赞 2019-03-21 20:44:53
    对于串口数据发送和接收,大多是都是利用串口中断来进行的,但是这样对于编程方面有一定要求,并且程序也不太好写,比如说,如果让你随意接收一段数据,然后利用串口将它发送出来,第一个需要考虑的问题就是接收...
  • 1. 打开串口 import serial com = serial.Serial('COM3', 9600) print com 2. 发送数据 import serial com = serial.Serial('COM3', 9600) success_bytes = com.write('This is data for test') print success_...
  • #ifndef READPORT_H #define READPORT_H #include<iostream> #include <string> #include <vector>...using namespace std;... // 打开串口,成功返回true,失败返回false // portname(串口名)
  • STM32之串口DMA接收不定长数据

    万次阅读 多人点赞 2018-09-17 15:49:25
    STM32之串口DMA接收不定长数据 本文为杰杰原创,如需转载请说明出处 引言 在使用stm32或者其他单片机的时候,会经常使用到串口通讯,那么如何有效地接收数据呢?假如这段数据是不定长的有如何高效接收呢? ...
  • STM32CUBEMX配置教程(九)STM32串口DMA收发数据 基于STM32H743VI 使用STM32CUBEMX两年了,始终觉得这个工具非常的方便,但因为不是经常使用,导致有些要点总是会有些遗忘,因此写下这一系列教程以供记忆,顺便让我...
  • 串口通信中,我们很多时候是需要接收不定长的数据,并且对接收数据放入到缓存中,等待接下来的处理。 整一个流程大致如下: 实现方法: 串口 空闲中断; DMA接收数据:(循环模式、不使用中断)1、可以得知...
  • 通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种异步收发传输器。首先先来介绍以下同步和异步通信,同步是指,发送方发出数据后,等接收方发回响应以后才发下一个数据包的...
  • 实现芯片串口收发数据,按键中断串口发送数据:按下按键,向串口发送数据,并通过虚拟终端显示出来; 串口接收数据中断来控制LED亮/灭:通过串口助手向MCU发送数据,“A”把LED灯点亮,“B”把LED灯熄灭。 led_key.c...
  • QT笔记-串口数据接收发送

    千次阅读 2020-04-25 14:03:26
    1.串口数据接收与发送 2.当打开A按钮B按钮无法使用 3.下拉框,文本框使用 4.下拉框选择内容发送至文本框显示 注意事项 串口函数的使用需在.pro文件内添加QT += core gui serialport 代码示例 .pro #----------------...
  • 本文在探讨传统数据收发不足之后,介绍如何使用带FIFO的串口来减少接收中断次数,通过一种自定义通讯协议格式,给出帧打包方法;之后介绍一种特殊的串口数据发送方法,可在避免使用串口发送中断的情况下,提高系统的...
  • printf向串口发送一些字符串数据。如果使用串口2,可以修改while((USART1->SR&0X40)==0);和USART1->DR = (u8) ch; 中的USART1为USART2. //加入以下代码,支持printf函数,而不需要选择use MicroLIB #if 1 ...
  • 串口通信中接收数据时延迟处理与缓存处理的解决方案(C#)利用串口进行通信,当发送方(A)将数据写入串口后,通过无线或有线方式将数据传送给接收方(B),B通过调用串口读方法comm.read(参数)即可将数据读出。...
  • stm32串口接收不到数据的一些问题

    万次阅读 2022-01-02 17:54:02
    菜鸟写的经验,大佬勿喷!...正点原子这个printf函数已经重映射到串口1了,这样的话就相当于在USART2_IRQHandler中断函数里面嵌套了另外一个串口发送中断。问题就是自己定义的usart2中断优先级比print
  • // 串口接收数据串行信号线 1101_1000 ,转为并行数据,取反截取低4位 传递给led,再传递给data_gen, // 发送数据: 0.1ms生成/发送一位数据,发送字符串"==HELLO WORLD=" (对应ASCII码),以及led值 1、源文件 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 58,975
精华内容 23,590
关键字:

串口1设置接收数据等待