精华内容
下载资源
问答
  • 转载自:... TTY驱动程序架构: 1. TTY概念解析  1.1 /dev/ttySCA0  1.2 /dev/tty1-n  1.3 /dev/console  在Linux系统中,终端是一类字符型设备,它包括多种类

    转载自:http://blog.csdn.net/coding__madman/article/details/51457181

    TTY驱动程序架构

    1. TTY概念解析

        1.1 /dev/ttySCA0

        1.2 /dev/tty1-n

        1.3 /dev/console

          在Linux系统中,终端是一类字符型设备,它包括多种类型,通常使用tty来简称各种类型的终端设备。

          . 串口终端(/dev/ttyS*)

          串口终端是使用计算机串口连接的终端设备。Linux把每个串行端口都看做是一个字符设备。这些串行端口所对应的设备名称是/dev/ttySAC*;

           .控制台终端(/dev/console)

           在Linux系统中,计算机的输出设备通常被称为控制台终端,这里特指printk信息输出到设备。/dev/console是一个虚拟的设备,它需要映射到真正的tty上,比如通过内核启动参数“console=ttySCA0”就把console映射到了串口0

          . 虚拟终端(、dev/tty*)

          当用户登录时,使用的是虚拟终端。使用Ctcl+Alt[F1 - F6]组合键时,我们就可以切换到tty1、tty2、tty3等上面去。tty*就称为虚拟终端,而tty0则是当前所使用虚拟终端的一个别名。

    2. TTY架构分析



    下面来通过一个回溯功能从内核代码来印证上面一张图的tty架构各函数调用关系!

    第一红色箭头对应的函数就是上图中的driver_write()


    上图中第二个红色箭头部分:在该函数处加上一个dump_stack函数保存然后重新编译内核

    通过tftp下载到开发板启动内核会看到串口终端打印出这个函数调用的回溯信息!

    今天电脑难产了!编译内核用了好久,之前几分钟就搞定了!


    开发板启动内核然后dmesg命令查看回溯打印的信息(这里为什么没直接打印到串口要用dmesg和printk打印级别有关)


    这里打印的比较多,仔细看其实都是重复的这里我里面的一段复制粘贴下来:

    [cpp]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. [<c049c7c0>] (dump_stack+0x18/0x1c) from [<c0237670>] (s3c24xx_serial_start_tx+0x14/0xb4)  
    2. [<c0237670>] (s3c24xx_serial_start_tx+0x14/0xb4) from [<c023374c>] (uart_start+0x64/0x68)  
    3. [<c023374c>] (uart_start+0x64/0x68) from [<c0234cb4>] (uart_write+0xc0/0xe4)  
    4. [<c0234cb4>] (uart_write+0xc0/0xe4) from [<c021dd84>] (do_output_char+0x16c/0x1d8)  
    5. [<c021dd84>] (do_output_char+0x16c/0x1d8) from [<c021de28>] (process_output+0x38/0x54)  
    6. [<c021de28>] (process_output+0x38/0x54) from [<c021e978>] (n_tty_write+0x204/0x444)  
    7. [<c021e978>] (n_tty_write+0x204/0x444) from [<c021b808>] (tty_write+0x14c/0x244)  
    8. [<c021b808>] (tty_write+0x14c/0x244) from [<c021b958>] (redirected_tty_write+0x58/0x68)  
    9. [<c021b958>] (redirected_tty_write+0x58/0x68) from [<c00e5ca4>] (vfs_write+0xbc/0x150)  
    10. [<c00e5ca4>] (vfs_write+0xbc/0x150) from [<c00e5e14>] (sys_write+0x44/0x74)  
    11. [<c00e5e14>] (sys_write+0x44/0x74) from [<c002fb40>] (ret_fast_syscall+0x0/0x30)  

    上面的图显示了每个函数一层一层的调用关系,对照着上面的架构分析图来看是不是?(这里再把架构图贴上来)

    这函数dump_stack()功能好强大!(要是能做成图形化界面直接显示下面的图形结构真是逆天了)

    上面的有个函数n_tty_write函数其实是线路规程里面的write!


    下面先来分析串口初始化:先上图


    内核中2440、6410的串口部分用的都是s3c24xx.. 这个函数,内部实现都差不多,肯定是内核驱动人员偷懒了!

    串口驱动分析之初始化

    总结来说最重要的有四项工作:串口初始化、串口打开、串口读取操作、串口写操作

    内核代码里面最重要和串口相关文件一个是samsung.c,一个是s3c6400.c


    1. 串口驱动程序结构

    看下面的图(下面2. 串口中的重要数据结构那张分析流程图):首先用户空间的write串口写函数找到内核中对应的数据结构


    这里可以看到用户空间的write函数对应的file_operations中的 tty_write,这里还有一些其他的常用函数

    继续对照着下面的图看tty_write对应的应该是线路规程中的tty_ldisc_ops中的函数:


    同样可以从内核代码中找到线路规程的ops数据结构:


    这里总结一下用户空间的write函数会调用系统调用接口的tty-write, 然后tty-write又会调用线路规程里面n_tty_write。

    还是对照着下面的图继续分析,可以看到n_tty_write会调用tty_operations里面的函数,内核代码中n_tty_write函数有点长,这里截了两张图:



    下面来瞅瞅tty_operations结构定义:


    由这个可以看出n_tty_write又对应着这里的uart_write函数!跳来跳去的好麻烦啊!感觉都是套路!

    下面还是继续分析uart_write庐山真面目,同样可以从下面的图中可以看到uart_write又对应着驱动里面写函数:


    这里面有几个重要的数据结构:第二第三个箭头指向的部分:这里可以看到从struct uart_state结构中拿到了port端口号uart_port, 下面再跳到uart_start(tty)函数中瞅瞅:


    继续跳:


    从上图可以看出这个函数又通过port结构跳到ops里面的函数!其实port就是uart_ops数据结构类型!上面的图中可以函数这个数据结构里面有很多的函数指针!然后就可以利用这些函数指针在驱动层来操作硬件了!

    上面要特别注意struct uart_state数据结构,把上面截图中的一行代码扣出来分析:

    struct uart_state *state = tty->driver_data;

    可以看到这个数据结构是从tty的driver_data里面来的,那么这个数据结构又是怎么放到driver_data里面去的呢?这个是uart_open函数里面做的:


    从上面的函数中可以看出从uart_open函数中拿到state 然后将state放入tty的driver_data(void*型)结构中。

    下面继续分析state是如何获得的:


    从sourceInsight中可以看到state是从driver里面uart_state的数据结构中拿到的:



    上面分析了那么多其实总结最重要的几种数据结构的包含关系可以总结如下:

    uart_driver  ------>  uart_state  ------>  uart_port  ------>  uart_ops



    2. 串口驱动中的重要数据结构


    第一步串口调用过程都是以下面这张图来分析的,上一步中所说的下图都是这下面这张图




    3. 初始化分析

    老规矩,从原有的内核源码中开始分析!重复造轮子!

    在SI中打开samsung.c

    [cpp]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. module_init(s3c24xx_serial_modinit);  
    2. module_exit(s3c24xx_serial_modexit);  

    跳转到模块初始化函数代码部分:


    这里可以看到在模块初始化部分使用了uart_register_driver函数注册了一个串口驱动,下面来看看函数参数的类型:


    结合上面的第一步的分析和第二步的流程图看看是不是清晰多了!(这里分析的其实也是对照着上面的流程图来的)

    下面再来分析s3c6400.c文件中的模块初始化:


    继续跳:


    可以看到这个函数又调用了平台驱动注册函数(上一篇博文有详细讲解),注册平台驱动的时候,平台总线会将平台驱动和我们系统中的平台设备进行一一的匹配,如果有匹配的上的,他就会调用平台驱动的probe函数

    跳来跳去跳到这了:


    下面来细致的分析上面的函数:

    首先看第一个箭头所指的地方,看看这个结构体:


    这个数组存放的全部是uart_port的串口信息。

    然后会调用串口初始化函数:

    [cpp]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. <span style="color:#ff0000;">ret = s3c24xx_serial_init_port(ourport, info, dev);</span>  


    函数比较长这里做为两张图截了,可以看到这个函数主要是做一些初始化工作!其中比较重要的是上图中红色箭头所指部分,第一个箭头上一行首先是基地址初始化,这里使用的是静态映射(linux在启动的时候就把物理地址和虚拟地址之间的关系映射好了)!拿虚拟地址,拿中断号, 复位fifo



    跳回去继续分析probe函数:


    看看第一个箭头所指向的函数,这个函数主要建立uart_driver和uart_port之间的联系的:

    [cpp]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. /** 
    2.  *  uart_add_one_port - attach a driver-defined port structure 
    3.  *  @drv: pointer to the uart low level driver structure for this port 
    4.  *  @uport: uart port structure to use for this port. 
    5.  * 
    6.  *  This allows the driver to register its own uart_port structure 
    7.  *  with the core driver.  The main purpose is to allow the low 
    8.  *  level uart drivers to expand uart_port, rather than having yet 
    9.  *  more levels of structures. 
    10.  */  
    11. int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)  
    12. {  
    13.     struct uart_state *state;  
    14.     struct tty_port *port;  
    15.     int ret = 0;  
    16.     struct device *tty_dev;  
    17.   
    18.     BUG_ON(in_interrupt());  
    19.   
    20.     if (uport->line >= drv->nr)  
    21.         return -EINVAL;  
    22.   
    23.     state = drv->state + uport->line;  
    24.     port = &state->port;  
    25.   
    26.     mutex_lock(&port_mutex);  
    27.     mutex_lock(&port->mutex);  
    28.     if (state->uart_port) {  
    29.         ret = -EINVAL;  
    30.         goto out;  
    31.     }  
    32.   
    33.     state->uart_port = uport;  
    34.     state->pm_state = -1;  
    35.   
    36.     uport->cons = drv->cons;  
    37.     uport->state = state;  
    38.   
    39.     /* 
    40.      * If this port is a console, then the spinlock is already 
    41.      * initialised. 
    42.      */  
    43.     if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {  
    44.         spin_lock_init(&uport->lock);  
    45.         lockdep_set_class(&uport->lock, &port_lock_key);  
    46.     }  
    47.   
    48.     uart_configure_port(drv, state, uport);  
    49.   
    50.     /* 
    51.      * Register the port whether it's detected or not.  This allows 
    52.      * setserial to be used to alter this ports parameters. 
    53.      */  
    54.     tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);  
    55.     if (likely(!IS_ERR(tty_dev))) {  
    56.         device_init_wakeup(tty_dev, 1);  
    57.         device_set_wakeup_enable(tty_dev, 0);  
    58.     } else  
    59.         printk(KERN_ERR "Cannot register tty device on line %d\n",  
    60.                uport->line);  
    61.   
    62.     /* 
    63.      * Ensure UPF_DEAD is not set. 
    64.      */  
    65.     uport->flags &= ~UPF_DEAD;  
    66.   
    67.  out:  
    68.     mutex_unlock(&port->mutex);  
    69.     mutex_unlock(&port_mutex);  
    70.   
    71.     return ret;  
    72. }  

    ret = device_create_file(&dev->dev, &dev_attr_clock_source); //创建属性文件 这个驱动中会用到

    安装驱动我们在/sys/目录下看到的串口相关信息就是这个函数实现的:




    又是尼玛的跳来跳去,好几把套路卧槽!


    这里这个函数暂时就跳到这吧!心累!没完没了的!先顾大局!

    ret = s3c24xx_serial_cpufreq_register(ourport);//动态频率调节函数


    又是套路,这里暂时只要知道和cpu有关就行了,暂时放过!

    下面再来一张串口初始化分析流程图:


    至此为止整个串口初始化流程就分析完了!内核代码还真不是那么简单!

    先注册平台总线驱动,然后平台总线驱动和平台设备相匹配,匹配上了就会调用probe函数,然后probe函数就会执行一些初始化工作!

    展开全文
  • STM32串口初始化

    千次阅读 2018-08-19 16:53:19
    串口初始化的一般步骤: 1.GPIO时钟使能RCC_AHB 2.USART时钟使能RCC_APB 3.USART端口配置(调用GPIO_Init) 4.USART对应引脚复用映射GPIO_PinAFConfig 以PA9、PA10复用USART1为例,具体过程见代码: //关于...

    串口初始化的一般步骤:

    1.GPIO时钟使能RCC_AHB

    2.USART时钟使能RCC_APB

    3.USART端口配置(调用GPIO_Init)

    4.USART对应引脚复用映射GPIO_PinAFConfig

    以PA9、PA10复用USART1为例,具体过程见代码:

    //关于时钟使能RCC函数名称的含义:
    //AHBx、APBx是总线名称
    //寻找相关GPIO口对应的时钟使能函数的技巧:
    //在stm32f4xx_rcc.h下查找该GPIO口
    
    void usart_init()
    {
        GPIO_InitTypeDef GPIO_InitStructure;
    
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能GPIO时钟
        RCC_AHB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//使能USART1时钟
    
        //USART1端口配置
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
    
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource9 | GPIO_PinSource10, GPIO_AF_USART1); //USART1对应引脚复用映射
    }
    
    

     

    展开全文
  • 10.02 一个简单的串口初始化程序

    千次阅读 2016-10-02 23:04:29
    这个 代码主要是对串口初始化,然后有个中断子程序,每次向串口发送一个数据,串口就会把这个消息通过这个串口再次发送出去。 今天就到这里把,第二天。。。中间断了一天,慢慢把这个习惯养成把。恒。。。
    又放松了一天,看了一整天的电影啊:《2012世界末日》,《异次元骇客》,《社交网络》还有几个有关IT行业的纪录片:《奔跑吧代码|code rush》《java 4-ever》预告,连续看这些比较费脑的电影感觉是很奇妙的,特别是看完《社交网络》之后,感觉马克.扎克伯格真的很帅有木有,思维根本跟不上人家的语速有没有,更别说看电影来练习英语听力了,有些人真的是有着方面的天赋,不得不承认,但是每个人都有自己的撸,自己认真走好自己的撸也是不错的,哈。。。烧了一天脑,看完后有些迷茫,总感觉花费一天一天的时间来看电影不是一个好的生活方式,但是不知道现在应该做一些什么,所以是时候分析一下从这次开学之后自己的状态了。
    首先:这个学期我的目标是什么?
    1找到可以让自己生存下来的并且是有关编程方面的事情做。2确定一下自己到底考不考研究生。2如果确定不考研,在大三学年之后,掌握一门技能,并能依靠这个来支撑自己的基本生活。
    到底是考研还是什么吗?考研的话我现在是不是就应该开始准备了。问题来了:1我想不想考研;2我适合不适合考研;3我对考研了解多少;4我有没有一起考研的朋友;5我考研的话应该考哪个专业的;6考研考哪个学校;7考研的目标是就业还是继续深造;8考研能得到什么。
    1.不想;2.感觉自己不适合,对理论方面不是很感兴趣;3不是很了解,目前的印象是可以得到一个硕士文凭,毕业以后相对本科生来好找工作,且工资刚开始会高一些,但自己算的话,本科毕业找工作工作三年可以积累不少经验,之后考研可能会比较好,而且在今天看完《code rush》以后感觉IT行业确实是吃青春饭的,能早些积累经验还是早些积累把,退休以后没事还是可以继续高研究的吗,现在就是想早些实现经济独立,25岁之后可以出国去转一转;4如果考研的话我会选择考计算机软件方面的研究生,目前是没有找到志趣相投的伙伴;5计算机软件;6浙大,西北;7就业;8文凭,对自己的认识会高一些,认识到一些非常棒的朋友。
    现在分析完了,自己是不考研了,感觉好了不少。明天开始code,基本上好看的电影都看了一遍,感觉脑子都不够用了,一天涨涨的,若爆了,哈哈。。。
    下面把今天写的code贴上(…………)
    
    #include "reg51.h"
    
    typedef unsigned char u8;
    typedef unsigned int u16;
    
    void Usart() interrupt 4
    {
        u8 ReceiveData;
    
        ReceiveData=SBUF;
        RI=0;
        SBUF=ReceiveData;
        while(!TI); //
        TI=0;   
    }
    
    void UsartInit()
    {
        TMOD|=0X20;
        PCON|=0X80;
        SCON=0X50;//
        TH1=0XF3;
        TL1=0XF3;
        TR1=1;
        EA=1;
        ES=1;
        TR1=1;  
    }
    
    void main()
    {
        UsartInit();
        while(1);
    }

    这个 代码主要是对串口的初始化,然后有个中断子程序,每次向串口发送一个数据,串口就会把这个消息通过这个串口再次发送出去。
    今天就到这里把,第二天。。。中间断了一天,慢慢把这个习惯养成把。恒。。。

    展开全文
  • C# 编写串口程序

    千次阅读 2017-11-14 00:02:50
    最近参考百度《C#编写串口程序》的pdf做了一个串口调试工具,以此为模版用于开发更复杂的上位机软件,PDF中叙述很完整。需要了解编写过程的请认真看资料。 下面阐述一下几点: (1)需要调用serialPort类 ...

           最近参考百度《C#编写串口程序》的pdf做了一个串口调试工具,以此为模版用于开发更复杂的上位机软件,PDF中叙述很完整。需要了解编写过程的请认真看资料。


    下面阐述一下几点:

    (1)需要调用serialPort类         https://msdn.microsoft.com/zh-cn/library/system.io.ports.serialport(v=vs.110).aspx

          示例代码:

    public static void Main()
    {
        string name;
        string message;
        StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
        Thread readThread = new Thread(Read);
    
        // Create a new SerialPort object with default settings.
        _serialPort = new SerialPort();
    
        // Allow the user to set the appropriate properties.
        _serialPort.PortName = SetPortName(_serialPort.PortName);
        _serialPort.BaudRate = SetPortBaudRate(_serialPort.BaudRate);
        _serialPort.Parity = SetPortParity(_serialPort.Parity);
        _serialPort.DataBits = SetPortDataBits(_serialPort.DataBits);
        _serialPort.StopBits = SetPortStopBits(_serialPort.StopBits);
        _serialPort.Handshake = SetPortHandshake(_serialPort.Handshake);
    
        // Set the read/write timeouts
        _serialPort.ReadTimeout = 500;
        _serialPort.WriteTimeout = 500;
    
        _serialPort.Open();
        _continue = true;
        readThread.Start();
    
        Console.Write("Name: ");
        name = Console.ReadLine();
    
        Console.WriteLine("Type QUIT to exit");
    
        while (_continue)
        {
            message = Console.ReadLine();
    
            if (stringComparer.Equals("quit", message))
            {
                _continue = false;
            }
            else
            {
                _serialPort.WriteLine(
                    String.Format("<{0}>: {1}", name, message));
            }
        }
    
        readThread.Join();
        _serialPort.Close();
    }
    
    public static void Read()
    {
        while (_continue)
        {
            try
            {
                string message = _serialPort.ReadLine();
                Console.WriteLine(message);
            }
            catch (TimeoutException) { }
        }
    }
    (2)serialDataReceivedEventHandler委托: https://msdn.microsoft.com/zh-cn/library/system.io.ports.serialport.datareceived(v=vs.110).aspx#示例

    用来处理接受的数据。

    using System;
    using System.IO.Ports;
    
    class PortDataReceived
    {
        public static void Main()
        {
            SerialPort mySerialPort = new SerialPort("COM1");
    
            mySerialPort.BaudRate = 9600;
            mySerialPort.Parity = Parity.None;
            mySerialPort.StopBits = StopBits.One;
            mySerialPort.DataBits = 8;
            mySerialPort.Handshake = Handshake.None;
            mySerialPort.RtsEnable = true;
    
            mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
    
            mySerialPort.Open();
    
            Console.WriteLine("Press any key to continue...");
            Console.WriteLine();
            Console.ReadKey();
            mySerialPort.Close();
        }
    
        private static void DataReceivedHandler(
                            object sender,
                            SerialDataReceivedEventArgs e)
        {
            SerialPort sp = (SerialPort)sender;
            string indata = sp.ReadExisting();
            Console.WriteLine("Data Received:");
            Console.Write(indata);
        }
    }

    (3)try   catch

    try-catch 语句由一个 try 块后跟一个或多个 catch 子句构成,这些子句指定不同的异常处理程序。


    下面是项目的完整代码:

    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;
    
    namespace 串口配置工具
    {
        public partial class FormMain : Form
        {
            SerialPort sp = null;//声明串口类
            bool isOpen = false;//打开串口标志位
            bool isSetProperty = false;//属性设置标志位
            bool isHex = false;//十六进制显示标志位
            public FormMain()
            {
                InitializeComponent();
            }
            //初始化配置
            private void FormMain_Load(object sender, EventArgs e)
            {
                this.MaximumSize = this.Size;
                this.MinimumSize = this.Size;
                this.MaximizeBox = false;//禁止用最大化
    
                int i;
                for (i = 0; i < 15; i++)//最大支持到串口15,根据需求添加
                {
                    cbxCOMPort.Items.Add("COM" + (i + 1).ToString());
                }
                cbxCOMPort.SelectedIndex = 0;
    
                //列出常用的波特率
                cbxBaudRate.Items.Add("1200");
                cbxBaudRate.Items.Add("2400");
                cbxBaudRate.Items.Add("4800");
                cbxBaudRate.Items.Add("9600");
                cbxBaudRate.Items.Add("19200");
                cbxBaudRate.Items.Add("38400");
                cbxBaudRate.Items.Add("43000");
                cbxBaudRate.Items.Add("56000");
                cbxBaudRate.Items.Add("57600");
                cbxBaudRate.Items.Add("115200");
                cbxBaudRate.SelectedIndex = 3;
                //列出停止位
                cbxStopBits.Items.Add("0");
                cbxStopBits.Items.Add("1");
                cbxStopBits.Items.Add("1.5");
                cbxStopBits.Items.Add("2");
                cbxStopBits.SelectedIndex = 1;
                //列出奇偶校验位
                cbxParity.Items.Add("无");
                cbxParity.Items.Add("奇校验");
                cbxParity.Items.Add("偶校验");
                cbxParity.SelectedIndex = 0;
                //列出数据位
                cbxDataBits.Items.Add("8");
                cbxDataBits.Items.Add("7");
                cbxDataBits.Items.Add("6");
                cbxDataBits.Items.Add("5");
                cbxDataBits.SelectedIndex = 0;
                //默认显示char
                rbnChar.Checked = true;
            }
            //串口检测
            private void btnCheckCOM_Click(object sender, EventArgs e)//检测那些串口可用
            {
                bool comExistence = false;//有可用串口标志位
                cbxCOMPort.Items.Clear();
                
                for (int i = 0; i < 15; i++)
                {
                    try
                    {
                        SerialPort sp = new SerialPort("COM" + (i + 1).ToString());
                        sp.Open();
                        sp.Close();
                        cbxCOMPort.Items.Add("COM" + (i + 1).ToString());
                        comExistence = true;
    
                    }
                    catch (Exception)
                    {
                        continue;
                    }
    
                }
    
                if (comExistence)
                {
                    cbxCOMPort.SelectedIndex = 0;
                }
                else
                {
                    MessageBox.Show("没有找到串口!", "错误提示");
                }
    
            }
    
           
    
            /私有函数
            /*        检测串口是否设置        */
            private bool CheckPortSetting()
            {
                
                if (cbxCOMPort.Text.Trim() == "") return false;
                if (cbxBaudRate.Text.Trim() == "") return false;
                if (cbxDataBits.Text.Trim() == "") return false;
                if (cbxParity.Text.Trim() == "") return false;
                if (cbxStopBits.Text.Trim() == "") return false;
                return true;
            }
            /私有函数
            /*        检测发送数据        */
            private bool CheckSendData()
            {
                if (cbxCOMPort.Text.Trim() == "") return false;
                return true;
            }
            /私有函数
            /*       设置串口的属性        */
            private void SetPortProperty()
            {
                sp = new SerialPort();
                sp.PortName = cbxCOMPort.Text.Trim();//串口名称
                sp.BaudRate = Convert.ToInt32(cbxBaudRate.Text.Trim());//波特率
    
                float f = Convert.ToSingle(cbxStopBits.Text.Trim());//设置停止位
                if (f == 0)
                {
                    sp.StopBits = StopBits.None;
                }
                else if (f == 1.5)
                {
                    sp.StopBits = StopBits.OnePointFive;
                }
                else if (f == 1)
                {
                    sp.StopBits = StopBits.One;
                }
                else if (f == 2)
                {
                    sp.StopBits = StopBits.Two;
                }
                else
                {
                    sp.StopBits = StopBits.One;
                }
    
                sp.DataBits = Convert.ToInt16(cbxDataBits.Text.Trim());//设置数据位
                string s = cbxParity.Text.Trim();//设置奇偶位
    
                if (s == "无")
                {
                    sp.Parity = Parity.None;
                }
                else if (s == "奇校验")
                {
                    sp.Parity = Parity.Odd;
                }
                else if (s == "偶校验")
                {
                    sp.Parity = Parity.Even;
                }
                else
                {
                    sp.Parity = Parity.None;
                }
    
                sp.ReadTimeout = -1;//设置超时读取函数
                sp.RtsEnable = true;
    
                //定义 DataReceive 事件
    
                sp.ReceivedBytesThreshold = 1;
    
                sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);//该方法加载就运行,
    
                if (rbnHex.Checked)
                {
                    
                    isHex = true;
                }
                else
                {
                    isHex = false;
                }
    
    
            }
    
            private void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
    
    
                System.Threading.Thread.Sleep(100);//延时100ms等待数据接收
    
    
                this.Invoke((EventHandler)(delegate
                {
                    if (isHex == false)
                    {
    
                        tbxRecvData.Text += sp.ReadLine();
                    }
                    else
                    {
                        Byte[] ReceivedData = new Byte[sp.BytesToRead];//创建接受的数组
                        sp.Read(ReceivedData, 0, ReceivedData.Length);
                        String RecvDataText = null;
                        for (int i = 0; i < ReceivedData.Length - 1; i++)
                        {
                            RecvDataText += ("0x" + ReceivedData[i].ToString("X2") + " ");
                        }
                        tbxRecvData.Text += RecvDataText;
                    }
                    sp.DiscardInBuffer();
                }));
    
            }
    
            //打开串口
            private void btnOpenCOM_Click(object sender, EventArgs e)
            {
                if (isOpen == false)
                {
                    if (!CheckPortSetting())
                    {
                        MessageBox.Show("串口未设置!", "错误提示");
                        return;
    
                    }
                    if (!isSetProperty)
                    {
                        SetPortProperty();
                        isSetProperty = true;
                    }
                    try
                    {
                        sp.Open();
                        isOpen = true;
                        btnCheckCOM.Text = "关闭串口";
                        cbxCOMPort.Enabled = false;
                        cbxBaudRate.Enabled = false;
                        cbxDataBits.Enabled = false;
                        cbxParity.Enabled = false;
                        cbxStopBits.Enabled = false;
                        rbnChar.Enabled = false;
                        rbnHex.Enabled = false;   
                    }
                    catch (Exception)
                    {
                        isSetProperty = false;
                        isOpen = false;
                        MessageBox.Show("串口无效或已被占用!", "错误提示");
    
                    }
    
                }
                else
                {
                    try
                    {
                        sp.Close();
                        isOpen = false;
                        isSetProperty = false;
                        btnCheckCOM.Text = "打开串口";
                        cbxCOMPort.Enabled = true;
                        cbxBaudRate.Enabled = true;
                        cbxDataBits.Enabled = true;
                        cbxParity.Enabled = true;
                        cbxStopBits.Enabled = true;
                        rbnChar.Enabled = true;
                        rbnHex.Enabled = true;
                    }
                    catch (Exception)
                    {
                        MessageBox.Show("关闭时发生错误!", "错误提示");
    
                    }
    
    
    
                }
    
    
            }
            //发送数据
            private void btnSend_Click(object sender, EventArgs e)
            {
                if (isOpen)
                {
                    try
                    {
    
                        sp.WriteLine(tbxSendData.Text);
                        //MessageBox.Show("发送完成!", "错误提示");
    
                    }
                    catch (Exception)
                    {
                        MessageBox.Show("发送数据时发送错误!", "错误提示");
                        return;
                    }
    
    
                }
                else
                {
                    MessageBox.Show("串口尚未打开!", "错误提示");
                    return;
    
                }
    
    
                if (!CheckSendData())
                {
                    MessageBox.Show("请输入要发送的数据!", "错误提示");
                    return;
                }
    
            }
            //清楚缓冲区
            private void btnCleanData_Click(object sender, EventArgs e)
            {
    
                tbxRecvData.Text = "";
                tbxSendData.Text = "";
            }
    
    
    
     
        }
    }
    

    源代码下载链接:

    链接:http://pan.baidu.com/s/1o8iM0qQ 密码:tbii


    展开全文
  • C++编写串口通信程序

    万次阅读 多人点赞 2018-08-13 19:55:30
    声明:本博客的内容主要是本人学习其他串口通信博客之后的总结,主要参考的博客地址如下: https://blog.csdn.net/wlk1229/article/details/52566701 ... ...
  • STM32串口初始化与使用详解串口简介串口初始化具体步骤串口收发理论代码执行 串口简介 USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步串行接收发送器 即串口。是一个高度灵活的收发...
  • STM32-USART串口初始化配置

    千次阅读 2020-07-14 07:12:12
    串口参数初始化 void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct); 开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤) void NVIC_Init(NVIC_InitTypeDef* NVIC_Init...
  • VC++编写简单串口上位机程序

    万次阅读 多人点赞 2017-10-31 21:56:13
    VC++编写简单串口上位机程序 串口通信,MCU跟PC通信经常用到的一种通信...在图书管理找到了用VC++编写串口上位机的资料,参考书籍,用自己相当蹩脚的C++写出了一个简单的串口上位机程序,分享一下,体验一下单片机和
  • VC控件MSComm编写串口通信程序

    千次阅读 2015-05-11 18:56:39
    在众多网友的支持下,串口调试助手从2001年5月21日...公开推出我最初用VC控件MSComm编写串口通信程序的源代码,并写出详细的编程过程,姑且叫串口调试助手源程序V1.0或VC串口通讯源程序吧,我相信,如果你用VC编程,
  • Qt编写串口通信程序详解

    千次阅读 2013-03-13 14:32:52
    (说明:我们的编程环境是windows xp下,在Qt Creator中进行,如果在Linux下或直接用源码编写程序稍有不同,请自己改动。) ( 在Linux下写串口通信程序。 首先portName应该改为/dev/ttyS0, 然后QextSerialBase::...
  • Qt编写串口通信程序全程图文讲解

    万次阅读 多人点赞 2009-10-23 13:01:00
    (说明:我们的编程环境是windows xp下,在Qt Creator中进行,如果在Linux下或直接用源码编写程序稍有不同,请自己改动。)   在Qt中并没有特定的串口控制类,现在大部分人使用的是第三方写的qextserialport类,...
  • 用Windows API 编写串口通讯程序

    万次阅读 2010-06-13 10:05:00
     实际上,我并没有在VC上编写串口程序。记得大一下学期的课程实践上倒是在DOS环境下做个简单的串口通讯,可是就是因为太简单了,而且是DOS那种独占式的进程,所以现在要搬到VC和MFC界面应用程序环境中,...
  • 编写串口通信程序全程图文讲解

    千次阅读 2013-03-15 11:14:30
    (说明:我们的编程环境是windows xp下,在Qt Creator中进行,如果在Linux下或直接用源码编写程序稍有不同,请自己改动。) 在Qt中并没有特定的串口控制类,现在大部分人使用的是第三方写的qextserialport类,我们...
  • 串口配置,给出中断式串口通信,详细的寄存器作用解析作者:Justice_Gao日期:2017年7月29日问题描述:参考源代码中串口通信程序初始化设置以及通信的方式,比较难理解,和STM32F4的串口通信不同,特别是接收这里我...
  • STM32F746 利用HAL库编写串口驱动程序

    千次阅读 2017-03-04 22:51:32
    之前用hal库的时候都是用一些简单的,例如初始化一个IO用作LED指示,今天写的代码需要串口的例子,说真的看了官方的demo也没看出啥名堂,反而觉得用hal写串口驱动太麻烦了. 回顾下之前常见的串口写法,发送用的是阻塞式...
  • 转:http://blog.csdn.net/u010580186/article/details/51595227(说明:我们的编程环境是windows xp下,在Qt Creator中进行,如果在Linux下或直接用源码编写程序稍有不同,请自己改动。)在Qt中并没有特定的串口控制...
  • VC2005使用MSCOMM编写串口通讯程序

    千次阅读 2013-01-11 23:14:22
    近来又要做个串口通信的程序,由于以前没有做过,所以不知道怎么写,网上搜了一圈,全是在VC6.0下写的,于是找葫芦画瓢,好不容易总算成功了,只是我这里用的是VC2005,但是VC2005中是没有MSCOMM的,所以我们需要...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,592
精华内容 6,636
关键字:

编写串口初始化程序