首页 > 其他分享 >msm8909_wk2124_SPI转串口485

msm8909_wk2124_SPI转串口485

时间:2023-08-05 12:33:20浏览次数:44  
标签:wk2xxx 串口 spi num wk2124 gpio 485 rs485ctl1 port

项目使用的是高通的msm8909平台,采用广和通SC806开发板,开发环境采用Ubuntu18.04。SC806默认有两路串口,对项目来说不够使用,需要进行转接,所以采用了wk2124将一路SPI转换为4路串口,然后再加485芯片,转换为4路485接口。接下来详细看看整个配置过程。

概述

说明:本文档会将为开提供的官方文档的信息摘录过来,并在其基础上对驱动文件进行详细说明!

WK2124芯片能够实现将1路SPI转换成4路串口,WK 系列扩展的子通道的 UART 具备如下功能特点:
每个子通道 UART 的波特率、字长、校验格式可以独立设置,最高可以提供2Mbps 的通信速率。
每个子通道具备收/发独立的 256 级 FIFO,FIFO 的中断可按用户需求进行编程触发点且具备超时中断功能。

简单的示意图如下:

image-20230629152006553

  1. WK 芯片作 SPI 从设备和 CPU 端的主 SPI 需要连接的信号有 CS 信号(此信号不能一直拉低,需要用主 SPI 的 CS 信号控制)、CLK 信号、MOSI 信号、MISO 信号,具体连接方式如上图。

  2. IRQ 信号为 WK 芯片的中断输出信号,需要连接到 CPU 具有外部中断功能的GPIO 上。IRQ 引脚外部需要加上拉电阻。

  3. RST 作为复位引脚,在 SPI 拓展 4 串口的时候,可以不用连接到 CPU.直接使用阻容复位电路。

WK2124驱动工作框架

  1. WK 驱动工作在 linux 内核层,向上提供 4 个串口设备节点供应用层用户调用。也就是说 WK 驱动注册成功以后,在/dev/ 目录下会生成 ttysWK0、ttysWK1、ttysWK2、ttysWK3 共 4 个串口设备节点,应用层就可以按照操作普通串口节点的方式操作。

    image-20230629152707566

  2. WK 驱动需要和 WK 芯片进行数据交互,数据交互是通过 SPI 总线进行的,所以 WK 驱动会调用 SPI 总线驱动接口进行数据收发。

    image-20230805091918020

WK2124驱动简介

为开厂商提供了芯片的驱动程序,我们只需要配置设备树,把驱动放到相应的目录下即可。为开的驱动程序我已经放到了附件中,可以进行下载使用,也可以联系我直接发你。

关于wk2xxx_spi.c的具体分析,我将在《wk2124驱动详解》一文中深入说明,这里就不过多说明了。

调试记录

把一个驱动添加到自己的内核中大概要做的事情包括:

  1. 看原理图了解引脚配置
  2. 根据原理图进行设备树配置
  3. 修改驱动程序,解析设备树
  4. 修改驱动程序,添加自定义功能

大概如此吧,接下来详细看看。

原理图

关于WK2124芯片的接口原理图,点击下载WK2124_SPI接口原理图,其实项目开发中可以用不到这个,我只是找到了,就做个分享。

然后来看项目中的原理图,了解一下相关GPIO的配置吧。

image-20230805101437298

这部分展示了WK2124芯片的一个连接情况。从上面的原理图中,我做出如下分析:

  1. wk2124连接的spi总线是SPI3(并且是使用四路GPIO复用的,分别是GPIO 0,1,2,3)
  2. wk2124的reset脚接了gpio89
  3. wk2124的irq脚接了gpio92
  4. gpio97和gpio69分别做了485_1和485_2的收发控制引脚

目前来说,能读到的信息就是这些。

设备树

根据上面看原理图,得到了spi总线、reset和irq引脚配置、485控制引脚的gpio。那么接下来我们就开始配置设备树吧。

SPI3总线配置

我们需要把wk2124的驱动挂载在spi3总线上就需要确保spi3总线是存在的,可是事实上去设备树文件中查看的时候却只有spi0总线是存在的。对于这种情况,我们应该及时想到这一路spi是可复用的gpio复用出来的。于是就来看看gpio复用表。

image-20230805102852633

SPI3是通过4路GPIO复用得到的pin-func是1. 然后根据这些信息,我们去配置一个SPI3总线,具体配置方法可以参照SPI0

设备树配置路径: kernel/arch/arm/boot/dts/qcom/sc806-evk/msm8909.dtsi

首先为spi_3起个别名

image-20230805110841079

这一步不是必须的,这里只是为了和SPI0保持一致,实际上后期对spi3的引用依旧使用的是spi_3。然后配置spi_3节点:

/* like: spi3 dts Configure */
	spi_3: spi@78b7000 { /* BLSP1 QUP2 */
                compatible = "qcom,spi-qup-v2";
                #address-cells = <1>;
                #size-cells = <0>;
                reg-names = "spi_physical", "spi_bam_physical";
                reg = <0x78b7000 0x600>,
                      <0x7884000 0x23000>;
                interrupt-names = "spi_irq", "spi_bam_irq";
                interrupts = <0 97 0>, <0 238 0>;
                spi-max-frequency = <19200000>;
                pinctrl-names = "spi_default", "spi_sleep";
                pinctrl-0 = <&spi3_default &spi3_cs0_active>;
                pinctrl-1 = <&spi3_sleep &spi3_cs0_sleep>;
                clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
                         <&clock_gcc clk_gcc_blsp1_qup3_spi_apps_clk>;
                clock-names = "iface_clk", "core_clk";
                qcom,infinite-mode = <0>;
                qcom,use-bam;
                qcom,use-pinctrl;
                qcom,ver-reg-exists;
                qcom,bam-consumer-pipe-index = <8>;
                qcom,bam-producer-pipe-index = <9>;
                qcom,master-id = <86>;
	};

以上是我参考spi0,为spi3做的配置。其中spi_3: spi@78b7000 中的地址,需要联系主控厂商获取:

blsp_mapping

如图所示,需要配置的有Physical address, IRQ以及Consumer-producer pipes。不管是哪条spi总线,都由同一个驱动加载,其compatible没有区分,不同spi差异在于地址,中断号,gpio配置上。

通过上面的配置,编译boot并重新刷机之后,就dev下就可以找到spi3设备了。

挂载wk2124到SPI3

上面的SPI3 配置完成之后,接下来把wk2xxx这个设备挂载在spi3总线上:

设备树配置路径: kernel/arch/arm/boot/dts/qcom/sc806-evk/msm8909.dtsi

/* like: wk2xxx dts Configure */
&spi_3 {
	status = "okay";
	max-freq = <48000000>;
	wk2xxx_spi@00 {
		status = "okay";
		compatible = "qcom,wk2xxx_spi";
		reg = <0>;
		spi-max-frequency = <19200000>;
		type = <0>;
		reset_gpio = <&msm_gpio 89 1>;
		irq_gpio = <&msm_gpio 92 0>;
		cs-gpios = <&msm_gpio 2 0>;
		rs485ctl1-gpio = <&msm_gpio 97 1>;
		rs485ctl2-gpio = <&msm_gpio 69 1>;
		rs485ctl3-gpio = <&msm_gpio 88 1>;
		rs485ctl4-gpio = <&msm_gpio 31 1>;
	};
};
  1. status:如果要启用 SPI,那么设置为 okay,如不启用,设置为 disable
  2. wk2xxx_spi@00:由于硬件使用的是 SPI3 的 cs0 引脚,所以设置为 00.如果使用cs1,则设置为 01
  3. compatible:这里的属性必须与驱动中的结构体:of_device_id 中的成员compatible 保持一致。这个是 SPI 驱动匹配的关键。(关于驱动程序框架这里不过多说明)
  4. reg:此处与 wk2xxx_spi@00:保持一致。此处设置为:00
  5. spi-max-frequency:此处设置 spi 使用的最高频率。wk2xxx 芯片 spi 最高支持 10000000。
  6. reset_gpio:该选项在 SPI 驱动当中不是必须的。该 gpio 和 WK2xxx 芯片的复位引脚相连,用于控制芯片的复位。根据实际使用的 gpio 去修改。
  7. irq_gpio: 该 gpio 和 wk2xxx 芯片的 IRQ 引脚相连,用于接收 wk2xxx 芯片传递来的中断信号。估计具体使用的 GPIO 去修改。
  8. SPI 的工作模式设置,默认工作在 0 模式,所以在 dts 中没有单独设置。
  9. 485控制gpio。用于控制485的收发,需要在驱动中解析并使用。

驱动程序移植

为开提供的驱动程序中已经对reset脚、irq脚以及cs脚进行了解析是使用。所以对于这三个gpio我们不需要过多的关心。我们需要做的就是在wk2xxx的驱动中解析我们加入的4路485控制gpio。

probe的修改

我们需要知道的是,驱动程序注册完成以后,会回到当前驱动中执行驱动的probe函数,可以这么说,probe就相当于是驱动程序的main函数。

所以根据我们上面的思路,我们需要在probe中调用485控制引脚的解析函数。

修改路径:kernel/drivers/spi/wk2xxx_spi.c (由于wk2124于spi总线相连,属于一个spi设备,所以将其放在spi目录下)

static int wk2xxx_probe(struct spi_device *spi)
{
    //const struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 };
    const struct sched_param sched_param = { .sched_priority = 100 / 2 };
    uint8_t i;
    int ret, irq;
    uint8_t dat[1];
	static struct wk2xxx_port *s;
    #ifdef _DEBUG_WK_FUNCTION
        printk(KERN_ALERT "%s!!--in--\n", __func__);
    #endif
...
    //Obtain the GPIO number of CS signal
    ret=wk2xxx_spi_csgpio_parse_dt(&spi->dev,&cs_gpio_num);
    if(ret!=0){
        printk(KERN_ALERT "wk2xxx_probe(cs_gpio)  cs_gpio_num = 0x%d\n",cs_gpio_num);
        ret=cs_gpio_num;
        goto out_gpio;

    }

/* like: rs485ctl parse run in probe */
    //Obtain the GPIO number of rs485ctl1 signal
    ret=wk2xxx_spi_rs485ctl1_parse_dt(&spi->dev,&rs485ctl1_gpio_num);
    if(ret!=0){
        printk(KERN_ALERT "wk2xxx_probe(rs485ctl1_gpio)  rs485ctl1_gpio_num = 0x%d\n",rs485ctl1_gpio_num);
        ret=rs485ctl1_gpio_num;
        goto out_gpio;

    }
...

   /* Setup interrupt */
	ret = devm_request_irq(&spi->dev, irq, wk2xxx_irq,IRQF_TRIGGER_FALLING, dev_name(&spi->dev), s);
  
	if (!ret){
        printk(KERN_ALERT "devm_request_irq success. ret=%d.\n",ret);
        return 0;
    }

out_port:
	for (i=0; i<NR_PORTS; i++) {
        printk(KERN_ALERT "uart_remove_one_port:%ld. status= 0x%d\n",s->p[i].port.iobase,ret);
		uart_remove_one_port(&wk2xxx_uart_driver, &s->p[i].port);
	}
out_clk:
    kthread_stop(s->kworker_task); 
out_gpio:
    if(rs485ctl1_gpio_num>0){
        printk(KERN_ALERT "gpio_free(rs485ctl1_gpio_num)= 0x%d,ret=0x%d\n",rs485ctl1_gpio_num,ret);
        gpio_free(rs485ctl1_gpio_num);  
        rs485ctl1_gpio_num=0;
    }
	return ret;
}

probe函数很长,我做了简单的删除,在probe函数中我们首先添加几个gpio的解析函数的调用:

    //Obtain the GPIO number of rs485ctl1 signal
    ret=wk2xxx_spi_rs485ctl1_parse_dt(&spi->dev,&rs485ctl1_gpio_num);
    if(ret!=0){
        printk(KERN_ALERT "wk2xxx_probe(rs485ctl1_gpio)  rs485ctl1_gpio_num = 0x%d\n",rs485ctl1_gpio_num);
        ret=rs485ctl1_gpio_num;
        goto out_gpio;

    }

然后添加其解析失败处理逻辑:

    if(rs485ctl1_gpio_num>0){
        printk(KERN_ALERT "gpio_free(rs485ctl1_gpio_num)= 0x%d,ret=0x%d\n",rs485ctl1_gpio_num,ret);
        gpio_free(rs485ctl1_gpio_num);  
        rs485ctl1_gpio_num=0;
    }

我们紧接着来看wk2xxx_spi_rs485ctl1_parse_dt函数.

解析设备树

wk2xxx_spi_rs485ctl1_parse_dt 函数参考了cs脚gpio解析函数书写的,它接收两个参数:devrs485ctl1_gpio_num,事实上传入的rs485ctl1_gpio_num 是一个全局变量:

/* like: rs485ctl gpio number */
int rs485ctl1_gpio_num;
int rs485ctl2_gpio_num;
int rs485ctl3_gpio_num;
int rs485ctl4_gpio_num;

完全可以在函数内部直接赋值,不知道为开为什么要这样传址处理。不过无所谓了。我们继续来看这个解析函数:

其实这个函数不是很满足内核编码规范的,这个函数中实现了:解析设备树,申请gpio使用权,初始化gpio状态,三个功能。这在内核的编码规范中是不允许的,所以希望参考本文章的朋友能将这些功能分开写。

通过这个函数我们可以得到一个gpio号,也就是那个全局变量,之后的操作中,我们控制485的收发,就可以直接操作这个gpio了。

/* like: wk2xxx_spi_rs485ctl1_parse_dt */
static int wk2xxx_spi_rs485ctl1_parse_dt(struct device *dev,int *rs485ctl1_gpio)
{

	int rs485ctl1_flags; 
	#ifdef _DEBUG_WK_FUNCTION
        printk(KERN_ALERT "%s!!--in--\n", __func__);
	#endif
	*rs485ctl1_gpio = of_get_named_gpio_flags(dev->of_node, "rs485ctl1-gpio", 0,(enum of_gpio_flags *)&rs485ctl1_flags);
    if (!gpio_is_valid(*rs485ctl1_gpio)){
		printk(KERN_ERR"invalid wk2xxx_rs485ctl2_gpio: %d\n", *rs485ctl1_gpio);
		return -1;
    }
   
    if(	*rs485ctl1_gpio){
		if (gpio_request(*rs485ctl1_gpio , "rs485ctl1-gpio")){
            printk(KERN_ERR"gpio_request failed!! rs485ctl1_gpio : %d!\n",*rs485ctl1_gpio);
		    gpio_free(*rs485ctl1_gpio);
		    return  -100;
        }
    }
	printk(KERN_ERR"wk2xxx_rs485ctl1_gpio: %d", *rs485ctl1_gpio);
    gpio_direction_output(*rs485ctl1_gpio,1);// output high
	#ifdef _DEBUG_WK_FUNCTION
        printk(KERN_ALERT "%s!!--exit--\n", __func__);
	#endif
	return 0;
}

这里只写了ctl485_1的配置,其他的类推。

添加自定义功能

放在一起说的话,其实上面解析485控制引脚就是在配置自定义功能了。接下来我们真正去控制这个485串口的收发。对于485串口的原理,这里不过多的赘述了,后面有机会在单独写文章说说。简单来说,485的收信和发信都在一个控制引脚的控制下进行,当这个引脚拉高,此时485就进入发送态,引脚拉低,485进入接受态。所以对于我们这个需求来说,无非就是在485要发送消息之前将对应的控制引脚拉高,发完之后马上拉低。

对于上面这个需求,重点就在于开始发送发送完成的两个节点。

这里简单提一下上层调用串口发送数据的一个过程:

发送数据:用户空间需要发送数据,首先调用 write(),并把需要发送的数据传递到tty 缓存区.驱动层调用 wk2xxx_start_tx()告诉驱动有数据需要发送,WK2xxx 芯片产生中断,中断函数通过 wk2xxx_tx_chars()函数把 tty 缓存区的数据取出来,并把数据写入wk2xxx 芯片的发送 fifo,芯片再自动发送发送 fifo 中的数据。

接收数据:当 WK2xxx 芯片接收的数据都是暂时存在子串口的接收 fifo,当接收fifo 中数据个数到达设置的接收中断触点,芯片产生接收中断,中断函数通过wk2xxx_rx_chars()函数,从接收 fifo 中读出接收的数据,然后传递给 tty 缓存区。那么用户空间就可以通过 read()函数读到接收的数据。

流程如下:

image-20230805114932430

那我们的目标就很明确了,我们只需要在wk2xxx_tx_chars()函数中添加控制语句,即可控制485的收发了。我们来看这个函数:

先了解一下这个还是的被调过程,这个函数是在中断处理函数wk2xxx_port_irq()中被调用的,也就是出发了发送中断,到这个函数里面就是为了发送数据的。程序会判断,串口的循环队列里面是否有数据,如果有数据就发送,最后判断循环队列是否为空,如果为空就发送完成,调用stop停止发送,退出中断处理。对于我的需求,下面是我的程序:

static void wk2xxx_tx_chars(struct uart_port *port)
{   
    struct wk2xxx_port *s = dev_get_drvdata(port->dev);
    struct wk2xxx_one *one = to_wk2xxx_one(port, port);
    uint8_t fsr,tfcnt,dat[1],txbuf[256]={0};
    int count,tx_count,i;
	int len_tfcnt,len_limit,len_p=0;
	len_limit=SPI_LEN_LIMIT;

    if (one->port.x_char) {   
        wk2xxx_write_slave_reg(s->spi_wk,one->port.iobase,WK2XXX_FDAT_REG,one->port.x_char);
        one->port.icount.tx++;
        one->port.x_char = 0;
        goto out;
    }

    if(uart_circ_empty(&one->port.state->xmit) || uart_tx_stopped(&one->port)){
        goto out;
    }

    wk2xxx_read_slave_reg(s->spi_wk,one->port.iobase,WK2XXX_FSR_REG,&fsr);
    wk2xxx_read_slave_reg(s->spi_wk,one->port.iobase,WK2XXX_TFCNT_REG,&tfcnt); 
    if(tfcnt==0){
	    tx_count=(fsr & WK2XXX_FSR_TFULL_BIT)?0:256;
		#endif
    }else{
		tx_count=256-tfcnt;
    } 
    if(tx_count>200){
        tx_count=200;
    } 
	count = tx_count;
	i=0;
	while(count){
  		if(uart_circ_empty(&one->port.state->xmit))
     		break;
	   	txbuf[i]=one->port.state->xmit.buf[one->port.state->xmit.tail];
	   	one->port.state->xmit.tail = (one->port.state->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
	   	one->port.icount.tx++;
	   	i++;
		count=count-1;
        #ifdef _DEBUG_WK_TX
            printk(KERN_ALERT "tx_chars:0x%x--\n",txbuf[i-1]);
        #endif
    };

    #ifdef WK_FIFO_FUNCTION 
	len_tfcnt=i;    
	while(len_tfcnt){
    // 如果串口循环队列非空,就发送数据,这个时候拉高相应的控制引脚。
		if(len_tfcnt>len_limit){
            /* like: start to transfer data, the gpio of rs485ctl turn to high */
            wk2xxx_spi_rs485ioctl_high(one->port.iobase);
            wk2xxx_write_fifo(s->spi_wk,one->port.iobase,len_limit,txbuf+len_p);    
			len_p=len_p+len_limit;
			len_tfcnt=len_tfcnt-len_limit;
        }else{
            /* like: start to transfer data, the gpio of rs485ctl turn to high */
            wk2xxx_spi_rs485ioctl_high(one->port.iobase);
            wk2xxx_write_fifo(s->spi_wk,one->port.iobase,len_tfcnt,txbuf+len_p);
			len_p=len_p+len_tfcnt;
			len_tfcnt=0;
		}
	}
    #else
	    for(count=0;count<i;count++){
            wk2xxx_write_slave_reg(s->spi_wk,one->port.iobase,WK2XXX_FDAT,txbuf[count]);	
        }
    #endif
out:
    // 这个位置相对于原版程序改动比较大,原版程序这里需要读两次寄存器,浪费时间会导致接收数据丢失。我的程序中将两个寄存器值合并判断,降低时间要求。
    while(1) {
        wk2xxx_read_slave_reg(s->spi_wk,one->port.iobase,WK2XXX_FSR_REG,dat);
        printk("FSR: %08X\n", dat[0]);
        if ((dat[0]&0x05) == 0) { 
            wk2xxx_spi_rs485ioctl_low(one->port.iobase);
            break;
        }
    }

    if (uart_circ_chars_pending(&one->port.state->xmit) < WAKEUP_CHARS){
        uart_write_wakeup(&one->port); 
    }
    if (uart_circ_empty(&one->port.state->xmit)){
        wk2xxx_stop_tx(&one->port);
    }
}

在以上的修改代码中,涉及到两个gpio控制函数,如下:

这两个函数逻辑很简单,就不赘述了。

static void wk2xxx_spi_rs485ioctl_high(uint8_t port) {
    switch (port){
        case 1:
            gpio_set_value(rs485ctl3_gpio_num, RS485CTL_GPIO_HIGH);
            break;
        case 2:
            gpio_set_value(rs485ctl4_gpio_num, RS485CTL_GPIO_HIGH);
            break;
        case 3:
            gpio_set_value(rs485ctl1_gpio_num, RS485CTL_GPIO_HIGH);
            break;
        case 4:
            gpio_set_value(rs485ctl2_gpio_num, RS485CTL_GPIO_HIGH);
            break;
        default:
            break;
    }

}

static void wk2xxx_spi_rs485ioctl_low(uint8_t port) {
    printk("like: set ttysWK port %d to receive mode!", port);
    switch (port){
        case 1:
            gpio_set_value(rs485ctl3_gpio_num, RS485CTL_GPIO_LOW);
            break;
        case 2:
            gpio_set_value(rs485ctl4_gpio_num, RS485CTL_GPIO_LOW);
            break;
        case 3:
            gpio_set_value(rs485ctl1_gpio_num, RS485CTL_GPIO_LOW);
            break;
        case 4:
            gpio_set_value(rs485ctl2_gpio_num, RS485CTL_GPIO_LOW);
            break;
        default:
            break;
    }

}

说明

本文章系项目总结时编写,如果疑问可以联系博主解答。

附件

原版wk2xxx_spi.c <--- 点击下载

原版wk2xxx.h <--- 点击下载

修改wk2xxx_spi_klelee.c <--- 点击下载

wk2124数据手册 <--- 点击下载

标签:wk2xxx,串口,spi,num,wk2124,gpio,485,rs485ctl1,port
From: https://www.cnblogs.com/klelee/p/wk2124_driver.html

相关文章

  • P4850 [IOI2009] Raisins 题解
    前言:IOI还出这样水的纯记忆化搜索题?还是T4?真令人难以置信。题意:题目传送门一个N×M的矩阵,对于任意一个子矩阵,只能横着或竖着分割,并且分割一次的价值为改子矩阵的元素之和,现要将该矩阵分割成1×1的方格,求最小的分割总价值之和。思路:看到这是个最优化的题,且数据范围很......
  • CT485modbus协议RS485接口开启合口式电流互感器传感器变送器
    www.daq-iot.com 19936624857—————————————————————————— SC-GP-CT485开口式电流互感器是上海数采物联网科技有限公司推出的一款可以把交流电模拟信号转换成485数字信号的一种电流传感器(互感器),产品内置32位ARM系列MCU和高精度计量芯片,经多点校......
  • Mitsubishi 三菱FX3U的232通信板,与PC串口调试助手通信测试
    在某个项目中,需要用到上位机来控制PLC中的气缸,采用的通信方式是无协议通信,硬件使用FX3U的PLC以及一块FX3U-232C-BD扩展板。具体测试如下所示。01使用硬件 如图所示: 02测试软件03具体步骤1、编写PLC控制程序,如图所示:程序解释:D8120是通信格式设置地址,设置成H0C81(二进制......
  • 三菱Q系列PLC串口和台达变频器进行RTU通信
    ▎一、动作描述1.三菱Q系列串口和台达变频器进行RTU通信2.通信内容:正反转停止控制▎二、前置基础1.Q系列串口通讯重要指令:U:模块的起始IO编号(以16进制数4位表示时的高3位)例如:起始IO为0070——U7n1:K1表示第1通道,K2表示第2通道n2:协议连续执行数,最大8个S:起始软元件(看下......
  • RS485自由转PROFINET网关RS485自由通讯协议
    捷米JM-RS485/232-PN(RS485转Profinet)将具有RS485/232接口、自由通信协议接口的设备与PROFINET相连,作为PROFINET现场总线系统的一个设备。捷米JM-RS485/232-PN集成了一个2端口交换机。受支持的以太网服务:ping、arp、SNMP和LLDP。端口诊断。禁用端口。实时、等时同步实时通信(RT......
  • zynq7000 I2C RTC 与 串口使用
     RS485串口测试硬件上2路串口,其中UART1对应PSSTDIN/OUT,UART0对应RS485;图‑1RS485电路,自动转换输入、输出方向可参考https://blog.csdn.net/qq_39400113/article/details/122387133图‑2使能2路串口图‑3先查看串口设备状态其中0对应UART串口,1对应RS485......
  • 串口通信
    UART、I2C、SPI、USB的异同点#通信协议#​​​​​名称引脚双工时钟电平设备通信距离传输速率USARTTX、RX全双工异步单端点对点远(最多1200m)慢(波特率设置)I2CSCL、SDA半双工同步单端多设备(一主多从,寻址)近慢SPISCLK、MOSI、MISO、CS全双工同......
  • SerialPort串口操作类C#实现
    usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.IO.Ports;namespacecommunicationComm{/********************************************************************************//打开串口(打开串口后不能修......
  • RS232转Profinet网关rs232和rs485的区别
    在工业自动化领域,如何将扫码枪与PLC连接一直是一个重要的问题。而今天,我们将通过一个案例来展示如何通过RS232转Profinet网关,将X-9300扫码枪接入到PLC1200工业以太网总线上。在这个过程中,我们将会用到捷米的RS232自由协议转Profinet网关。1, 首先,我们需要了解RS232和Profinet两......
  • stm32串口USART 硬件流控(转载)
    尊重原创,分享学习,内容来源:stm32串口USART硬件流控--学习笔记-国产零零柒-博客园(cnblogs.com)    流控的概念源于RS232这个标准,在RS232标准里面包含了串口、流控的定义。大家一定了解,RS232中的“RS”是RecommendStandard的缩写,即”推荐标准“之意,它并不像......