当前位置: 首页 > wzjs >正文

廊坊网站建设咨询青橙网络创建网站免费注册

廊坊网站建设咨询青橙网络,创建网站免费注册,旅游网站的建设背景,哪个网站可以做行程攻略Linux驱动开发-①I2C驱动②spi驱动③uart驱动 一,I2C驱动1.AP3216C2.I2C设备不需要内存映射 二,SPI驱动2.1 icm20608c2.1.1 实现原理2.1.2 工作流程2.1.3驱动实现2.1.4 相关问题① MMIO设备和I2C/SPI设备② read函数和write函数中,为什么采用…

Linux驱动开发-①I2C驱动②spi驱动③uart驱动

  • 一,I2C驱动
    • 1.AP3216C
    • 2.I2C设备不需要内存映射
  • 二,SPI驱动
    • 2.1 icm20608c
      • 2.1.1 实现原理
      • 2.1.2 工作流程
      • 2.1.3驱动实现
      • 2.1.4 相关问题
      • ① MMIO设备和I2C/SPI设备
      • ② read函数和write函数中,为什么采用kmalloc函数
      • ③DMA技术
      • ④cs-gpios
      • ⑤同步串行和异步串行
  • 三,UART驱动
    • 3.1 UART驱动
    • 3.2 关于 I2C、SPI、TTL、RS232、RS485和RS422
      • 3.2.1 TTL UART和RS232、RS485和RS422的关系
      • 3.2.2 RS485能一主多从,但是RS232只能点对点
      • 3.2.3 帧

一,I2C驱动

1.AP3216C

  类似于裸机驱动,将I2C总线具体处理分成一部分总线驱动(已经写好的),针对具体设备再分成一部分(使用时候,针对读写建立特定结构体,使用i2c_transfer函数进行设备和总线的读写工作)。
  总体思想:i2c_driver类似于platform结构,也需要prob函数和remove函数,需要建立of表匹配设备树中compatible属性,特点:①i2c_client描述设备信息结构体,包含i2c_adapter总线控制器,总线控制器结构体里面又有i2c_transfer函数,具体实现设备和总线之间的读写。②在probe函数中,将i2c_client传递到ap3216c_dev结构体中(全局变量中),从而能够在其他地方调用i2c_client的数据和i2c_transfer函数。
  驱动程序:①关键是i2c_driver框架的建立。②ap3216c_read_reg和ap3216c_write_reg函数的实现,即i2c_msg结构体变量内容的设置。

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/fs.h>  // 包含 register_chrdev_region 的定义
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/semaphore.h>
#include<linux/platform_device.h>
#include<linux/i2c.h>
#include<linux/delay.h>
#define AP3216C_NAME "ap3216c"
#define AP3216C_SYSTEMCONG 0x00 /* 配置寄存器 */
#define AP3216C_INTSTATUS 0X01 /* 中断状态寄存器 */
#define AP3216C_INTCLEAR 0X02 /* 中断清除寄存器 */
#define AP3216C_IRDATALOW 0x0A /* IR 数据低字节 */
#define AP3216C_IRDATAHIGH 0x0B /* IR 数据高字节 */
#define AP3216C_ALSDATALOW 0x0C /* ALS 数据低字节 */
#define AP3216C_ALSDATAHIGH 0X0D /* ALS 数据高字节 */
#define AP3216C_PSDATALOW 0X0E /* PS 数据低字节 */
#define AP3216C_PSDATAHIGH 0X0F /* PS 数据高字节 */
struct ap3216c_dev{struct class *class;struct device *device;struct cdev cdev;dev_t ap3216c_hao;int major;//主设备号int minor;//次设备号struct i2c_client *private_date;unsigned short ir,ps,als;};
struct ap3216c_dev ap3216c;
static u8 ap3216c_read_reg(struct ap3216c_dev *ap3216c_read, u8 reg)
{int ret;struct i2c_client *client = ap3216c.private_date;//传递数据struct i2c_msg msg[2];u8 buf;msg[0].addr  = client->addr;//设备地址msg[0].flags = 0;//写操作msg[0].len   = 1;msg[0].buf   = &reg;//寄存器msg[1].addr  = client->addr;//设备地址msg[1].flags = I2C_M_RD;//读msg[1].len   = 1;msg[1].buf   = &buf;//把最终读到的数据放到buff中ret = i2c_transfer(client->adapter, msg, 2);if (ret < 0) {printk(KERN_ERR "error %d\n", ret);buf = 0xff;}return buf;
}
static void ap3216c_write_reg(struct ap3216c_dev *ap3216c_write, u8 reg,u8 data)
{u8 b[3];struct i2c_client *client = ap3216c.private_date;//传递数据struct i2c_msg msg[1];b[0]=reg;//寄存器地址放在首位memcpy(&b[1],&data,1);//每次写入一个数据msg[0].addr  = client->addr;//设备地址msg[0].flags = 0;//写操作msg[0].len   = 2;//长度为2msg[0].buf   = b;//b中放的先是寄存器地址,后面是数据i2c_transfer(client->adapter, msg, 1);
}
/*读写数据操作*/
void ap3216c_read_data(struct ap3216c_dev *dev)
{unsigned char buf[6]={0};int i =0;for(i=0;i<6;i++){buf[i] = ap3216c_read_reg(dev,AP3216C_IRDATALOW+i);}if(buf[0] & 0X80) /* IR_OF 位为 1,则数据无效 */dev->ir = 0;else /* 读取 IR 传感器的数据 */dev->ir = ((unsigned short)buf[1] << 2) | (buf[0] & 0X03);dev->als = ((unsigned short)buf[3] << 8) | buf[2];/* ALS 数据 */if(buf[4] & 0x40) /* IR_OF 位为 1,则数据无效 */dev->ps = 0;else /* 读取 PS 传感器的数据 */dev->ps = ((unsigned short)(buf[5] & 0X3F) << 4) |(buf[4] & 0X0F);
}
static int ap3216c_open(struct inode *innode,struct file *filp)
{unsigned char result = 0;filp->private_data = &ap3216c;//将ap3216c结构体数据设为私有数据ap3216c_write_reg(&ap3216c,AP3216C_SYSTEMCONG,0x04);//写入寄存器数据mdelay(50);ap3216c_write_reg(&ap3216c,AP3216C_SYSTEMCONG,0x03);//写入寄存器数据result =ap3216c_read_reg(&ap3216c, AP3216C_SYSTEMCONG);printk("AP3216C_SYSTEMCONG = %d \r\n",result);return 0;
}
static int ap3216c_release(struct inode *innode,struct file *filp)
{  return 0;
}
static ssize_t ap3216c_read(struct file *filp, char __user *buf,size_t cnt,loff_t *offt)
{int ret = 0;unsigned short buff[3];ap3216c_read_data(&ap3216c);buff[0]=ap3216c.ir;buff[1]=ap3216c.als;buff[2]=ap3216c.ps;ret = __copy_to_user(buf,buff,sizeof(buff));return ret;
}
static ssize_t ap3216c_write(struct file *filp, const char __user *buf,size_t cnt,loff_t *offt)
{return 0;
}
static struct file_operations ap3216c_fops={.owner=THIS_MODULE,.read=ap3216c_read,.write=ap3216c_write,.open=ap3216c_open,.release=ap3216c_release,
};
static int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{/*注册*//*1.设备号*/if(ap3216c.major){ap3216c.ap3216c_hao = MKDEV(ap3216c.major,0);register_chrdev_region(ap3216c.ap3216c_hao, 1, AP3216C_NAME);//主动注册}else{alloc_chrdev_region(&ap3216c.ap3216c_hao, 0, 1, AP3216C_NAME);//自动注册}printk("major = %d,minor = %d",MAJOR(ap3216c.ap3216c_hao),MINOR(ap3216c.ap3216c_hao));/*2.注册函数*/ap3216c.cdev.owner = THIS_MODULE;cdev_init(&ap3216c.cdev,&ap3216c_fops);cdev_add(&ap3216c.cdev,ap3216c.ap3216c_hao,1);/*3.节点申请*/ ap3216c.class = class_create(THIS_MODULE,AP3216C_NAME);ap3216c.device = device_create(ap3216c.class, NULL,ap3216c.ap3216c_hao, NULL,AP3216C_NAME);ap3216c.private_date = client;//传递数据return 0;
}
static int ap3216c_remove(struct i2c_client *client)
{printk("exit in linux\r\n");cdev_del(&ap3216c.cdev);//先删除设备unregister_chrdev_region(ap3216c.ap3216c_hao,1);//删除设备号device_destroy(ap3216c.class,ap3216c.ap3216c_hao);//先删除和设备关系class_destroy(ap3216c.class);//再删除类return 0;
}
static const struct i2c_device_id ap3216c_id[] = {{ "ap3216c", 0 },{ }
};
const struct of_device_id	ap3216c_of_match[]={{.compatible = "wyt-ap3216c"},{ /*sentinel*/ },
};
static struct i2c_driver ap3216c_driver = {.probe		= ap3216c_probe,.remove		= ap3216c_remove,.driver		= {.owner = THIS_MODULE,.name	= "ap3216c666",//1.无设备树,匹配名字.of_match_table = ap3216c_of_match,//2.有设备树,直接利用设备树中compatible属性},.id_table = ap3216c_id,
};
static int __init ap3216c_init(void)
{ int ret = 0;ret = i2c_add_driver(&ap3216c_driver);return ret;
}
static void  __exit ap3216c_exit(void)
{i2c_del_driver(&ap3216c_driver);  
}
/*驱动入口和出口*/
module_init(ap3216c_init);
module_exit(ap3216c_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyt");

2.I2C设备不需要内存映射

  简单来说,I2C设备就不在内存中,它接的是具体硬件,那还怎么会需要地址映射呢,直接对设备地址和寄存器地址进行操作就行了(访问通过数据包传输,而非直接读写内存地址)。
在这里插入图片描述

二,SPI驱动

2.1 icm20608c

2.1.1 实现原理

  流程:spi驱动包含spi控制器驱动和spi设备驱动,控制器部分驱动已经做好,也就是说在设备驱动中可以调用其中的读写函数,实现数据的具体读写。同样和i2c设备驱动差别不大,spi设备驱动也类似于platform框架,具体操作包括:①在init和exit函数中进行注册和注销。②对spi_driver结构体变量的内容进行设置,主要包括of_match_table对compatible属性设置,probe和remove函数,name等设置。③在probe函数中实现设备号和节点的注册,以及设置spi工作模式设置,然后进行spi_setup注册。④读和写函数设置,spi_transfer结构体内数据的设置(想要写出的数据或者是准备接收数据要放的位置,用指针接收),最终的信息以spi_message形式,因此将spi_transfer添加到spi_message中。
  注意的是spi是全双工,因此发送数据的同时也在一直接收数据,比如想要读取某个寄存器的值,先发送读标志位加寄存器值(读标志位在最高位,为1,和j寄存器reg进行或运算),发送这个1|reg的同时,也接收了一个数据,如果把接收数据放到指针data位置,那么data[0]这个数据其实并不是寄存器中的数据,data[1]才是寄存器中的数据。

2.1.2 工作流程

①主机拉低 CS 选择从机。
②主机生成时钟 SCLK,同时在 MOSI 上逐位发送数据。
③从机在 MISO 上同步返回数据(每个时钟周期同时收发一位)。
④传输完成后,主机拉高 CS。

2.1.3驱动实现

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/fs.h>  // 包含 register_chrdev_region 的定义
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/semaphore.h>
#include<linux/platform_device.h>
#include <linux/spi/spi.h>          // SPI 核心头文件(必须)
#include<linux/delay.h>
#include"spi_my.h"
#define IMC20608C_NAME  "icm20608c"struct icm20608c_dev {int major;int minor;dev_t ID;struct class *class;struct cdev cdev;struct device *device;struct device_node *nd;int gpio;//gpiostruct spi_device *icm20608c_spi_private_data;signed short accel_x_adc,accel_y_adc,accel_z_adc,temp_adc,gyro_x_adc, gyro_y_adc,gyro_z_adc ;
};
static struct icm20608c_dev  icm20608c;
static void  icm20608c_read_regs(struct icm20608c_dev *dev,u8 reg,void *buf,int len)
{int ret = 0;unsigned char txdata[1];//发送的数据,即读标志位+reg寄存器unsigned char *rxdata;//设备中的数据,读到的struct spi_message m;struct spi_device *spi = dev->icm20608c_spi_private_data;struct spi_transfer *t ;// gpio_set_value(icm20608c.gpio,0);t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);rxdata= kzalloc(len+1,GFP_KERNEL);if(!rxdata){goto out_rxdata;}/*spi为全双工,放入读标志,并且放入寄存器值,说明要读取多少个数据,读到后放入rxdata中*/txdata[0]=reg|0x80;//读最高位为1 t->tx_buf =txdata;t->rx_buf = rxdata; //让两个指针=,指向同一个数据t->len = len+1;spi_message_init(&m);spi_message_add_tail(t, &m);ret = spi_sync(spi, &m);if(ret){goto out_spi_sync;}// printk(" read len  =%x\r\n",t->len);// printk(" read t->tx_buf  reg=%x\r\n",((uint8_t*)t->tx_buf)[0]);    // printk(" read t->rx_buf[0]=%x\r\n",((uint8_t*)t->rx_buf)[0]);// printk(" read t->rx_buf[1]=%x\r\n",((uint8_t*)t->rx_buf)[1]);// printk(" read t->rx_buf[2]=%x\r\n",((uint8_t*)t->rx_buf)[2]);memcpy(buf, rxdata+1, len);out_spi_sync:kfree(rxdata);
out_rxdata:kfree(t);// gpio_set_value(icm20608c.gpio,1);
}
static void  icm20608c_write_regs(struct icm20608c_dev *dev,u8 reg,void *buf,int len)
{unsigned char *txdata;//发送的数据,第一个是标志位+reg寄存器,其于为写入第数据struct spi_device *spi = dev->icm20608c_spi_private_data;// gpio_set_value(icm20608c.gpio,0);txdata = kzalloc(len+1,GFP_KERNEL);txdata[0]=reg &~0x80;memcpy(&txdata[1],buf,len);spi_write(spi, txdata, len+1);kfree(txdata);// gpio_set_value(icm20608c.gpio,1);
}static  unsigned  char icm20608c_read_one_reg(struct icm20608c_dev *dev,u8 reg)
{unsigned char result_one_reg;icm20608c_read_regs(&icm20608c,reg,&result_one_reg,1);return result_one_reg;
}
void icm20608c_write_one_reg66(struct icm20608c_dev *dev,u8 reg,unsigned char data)
{icm20608c_write_regs(&icm20608c,reg,&data,1);
}static int icm20608c_release (struct inode *node , struct file *filp)
{return 0;
}
static int icm20608c_open (struct inode *node, struct file *filp)
{filp->private_data = &icm20608c;return 0;
}
/*没填写函数内部分*/
static 	ssize_t icm20608c_read (struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{int ret = 0;unsigned char data[14] = { 0 };signed int result[7] = {0};struct icm20608c_dev *dev = (struct icm20608c_dev*)filp->private_data;icm20608c_read_regs(dev,ICM20_ACCEL_XOUT_H,data,14);result[3] = (signed int)((data[0] << 8) | data[1]);result[4] = (signed int)((data[2] << 8) | data[3]);result[5] = (signed int)((data[4] << 8) | data[5]);result[6] = (signed int)((data[6] << 8) | data[7]); result[1] = (signed int)((data[8] << 8) | data[9]);result[2] = (signed int)((data[10] << 8) | data[11]);   result[3] = (signed int)((data[12] << 8) | data[13]);ret = __copy_to_user(buf,result,sizeof(result));if(ret<0){ret = -1;}return ret; 
}/*文件操作函数*/
static struct file_operations icm20608c_fops={.owner = THIS_MODULE,.open = icm20608c_open,.release = icm20608c_release,.read = icm20608c_read,
};/*寄存器初始化*/
static void icm20608c_reg_init(void)
{u8 value = 0,ret = 0;icm20608c_write_one_reg66(&icm20608c, ICM20_PWR_MGMT_1,0x80);mdelay(50);icm20608c_write_one_reg66(&icm20608c, ICM20_PWR_MGMT_1,0x01);mdelay(50);ret = icm20608c_read_one_reg(&icm20608c, ICM20_PWR_MGMT_1);printk("ICM20_PWR_MGMT_1 = %X\r\n", ret);value = icm20608c_read_one_reg(&icm20608c, ICM20_WHO_AM_I);printk("ICM20608 ID = %X\r\n", value);icm20608c_write_one_reg66(&icm20608c, ICM20_SMPLRT_DIV, 0x00); icm20608c_write_one_reg66(&icm20608c, ICM20_GYRO_CONFIG, 0x18); icm20608c_write_one_reg66(&icm20608c, ICM20_ACCEL_CONFIG, 0x18); icm20608c_write_one_reg66(&icm20608c, ICM20_CONFIG, 0x04); icm20608c_write_one_reg66(&icm20608c, ICM20_ACCEL_CONFIG2, 0x04);icm20608c_write_one_reg66(&icm20608c, ICM20_PWR_MGMT_2, 0x00); icm20608c_write_one_reg66(&icm20608c, ICM20_LP_MODE_CFG, 0x00); icm20608c_write_one_reg66(&icm20608c, ICM20_FIFO_EN, 0x00); 
};const struct of_device_id of_icm20608c_table[]={{.compatible = "wyt,icm20608"},{}
};
const struct spi_device_id icm20608c_table[]={{"icm20608c",0},{ }
};
/*完成设备号注册 节点注册 spi设备初始化*/
static int icm20608c_probe(struct spi_device *spi)
{int ret = 0;/*1.设备号*/if(icm20608c.major){icm20608c.ID = MKDEV(icm20608c.major, 0);ret = register_chrdev_region(icm20608c.ID, 1, IMC20608C_NAME);}else {ret = alloc_chrdev_region(&icm20608c.ID, 0, 1, IMC20608C_NAME);icm20608c.major = MAJOR(icm20608c.ID);        }printk("major = %x\r\n",icm20608c.major);/*2.设备注册操作函数*/cdev_init(&icm20608c.cdev, &icm20608c_fops);icm20608c.cdev.owner = THIS_MODULE;ret = cdev_add(&icm20608c.cdev,icm20608c.ID, 1);if (ret < 0)goto err_unreg;/*3.类*/icm20608c.class = class_create(THIS_MODULE, IMC20608C_NAME);if (IS_ERR(icm20608c.class)) {ret = PTR_ERR(icm20608c.class);goto err_cdev;}/*4.节点*/icm20608c.device = device_create(icm20608c.class, NULL, icm20608c.ID, NULL, IMC20608C_NAME);if (IS_ERR(icm20608c.device)) {ret = PTR_ERR(icm20608c.device);goto err_class;}// icm20608c.nd=of_get_parent(spi->dev.of_node);// icm20608c.gpio = of_get_named_gpio(icm20608c.nd,"cs-gpio",0);// ret = gpio_request(icm20608c.gpio,"icm20608c");// ret = gpio_direction_output(icm20608c.gpio,1);// if(ret<0)// {//     printk("gpio error\r\n");// }/*5.初始化SPI设备*/spi->mode = SPI_MODE_0;//时钟模式spi_setup(spi);icm20608c.icm20608c_spi_private_data = spi;/*寄存器初始化内容*/icm20608c_reg_init();printk("probe success \r\n");return ret;
err_class:class_destroy(icm20608c.class);
err_cdev:cdev_del(&icm20608c.cdev);
err_unreg:unregister_chrdev_region(icm20608c.ID, 1);return ret;
}static int icm20608c_remove(struct spi_device *spi)
{cdev_del(&icm20608c.cdev);unregister_chrdev_region(icm20608c.ID, 1);device_destroy(icm20608c.class, icm20608c.ID);class_destroy(icm20608c.class);printk("remove success \r\n");return 0;
}static struct spi_driver icm20608c_driver={.probe = icm20608c_probe,.remove = icm20608c_remove,.driver = {.name = "icm20608c_spi_driver",.of_match_table = of_icm20608c_table,},.id_table = icm20608c_table,};static int __init  icm20608c_init(void)
{return spi_register_driver(&icm20608c_driver);
}
static void __exit icm20608c_exit(void)
{spi_unregister_driver(&icm20608c_driver);
}
/*驱动入口*/
module_init(icm20608c_init);
module_exit(icm20608c_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("WYT");

2.1.4 相关问题

① MMIO设备和I2C/SPI设备

在这里插入图片描述

② read函数和write函数中,为什么采用kmalloc函数

  kmalloc即动态分配内存,正常一个应用程序运行,会产生两个栈空间,用户栈(位于用户空间,用于存储函数调用、局部变量等用户态数据)和内核栈(位于内核空间,当进程通过系统调用或中断进入内核态时使用),执行read或者write函数时,cpu从用户态切换到内核态,在内核开辟栈空间,这个空间一般比较小,为8kb或者16kb,因此在read或者write函数中,①如果创建比较大的结构体变量或者是数组数据以及其他数据时候,其大小可能会超过栈空间,采用kmalloc函数在其他内存中开辟出空间,来放这些数据。②栈变量的声明周期仅限于函数执行期间,当函数执行完毕后,这个栈空间就没了,但是spi如果采用的是spi_async异步传输,即想等某些条件满足,再往数组里面写数据,但是这个时候read函数已经执行完毕了,栈空间都没了,就算有数据,也写不进来了,因此采用kmalloc函数开辟。

③DMA技术

  Direct Memory Access,就是不用CPU管了,减少CPU负担,直接能够让外设与内存交换数据,不用CPU管但是肯定要有一个管这个事情,即DMA控制器。模式:①内存到外设:视频流传输、网络通信,②外设到内存:比如摄像头,③内存到内存:比如磁盘之间数据拷贝。

④cs-gpios

cs-gpios 是设备树(Device Tree)中用于配置 SPI 设备的片选信号(Chip Select, CS),CS 引脚用于选择当前通信的从设备,确保同一时间只有一个设备响应主机的指令。

⑤同步串行和异步串行

  同步就是有时钟线,异步就是没有时钟线。
  同步串行:有时钟信号(SCLK):收发双方严格依赖共享时钟同步数据。连续传输:数据以固定长度的形式发送,无起始/停止位。高速高效:适合大数据量、高实时性场景(SPI I2C)。
  异步串行:无时钟信号:依赖预定义的波特率(Baud Rate)和起始/停止位同步。按字节传输:每个数据包(通常1字节)独立封装,带起始位和停止位。灵活性高:适合低速、间歇性数据传输。

三,UART驱动

3.1 UART驱动

uart_driver结构体变量主要是注册UART驱动到内核,uart_port描述UART硬件端口,即设备树中对复用属性和电器属性配置完成后,将这个与uart_port相关联。uart_ops,即uart_port里面的操作函数,实现具体功能。

3.2 关于 I2C、SPI、TTL、RS232、RS485和RS422

在这里插入图片描述

3.2.1 TTL UART和RS232、RS485和RS422的关系

  TTL UART是协议层面,就相当于是根基,RS232、RS485和RS422属于物理层,就相当于这个房子的外观,TTL想要实现什么样的效果,比如长距离传输,但是它这种方式实现不了,于是就通过芯片,比如MAX485将TTL的电平信号转化为了RS485的格式要求,从而实现了长距离传输。单片机 (TX/RX, TTL) → MAX485(控制DE/RE) → A/B差分线 MAX485(设备内部) →设备,有点像高压电,其他的也是如此,因此UART驱动,无论是RS什么方式,最终实现都是TTL,驱动是一样的。

3.2.2 RS485能一主多从,但是RS232只能点对点

  RS485实现一主多从:DE/RE 引脚,这个是MAX485芯片内的,DE为高电平,RS485发送,RE为低电平,RS485接收,通常用一个GPIO控制这俩引脚,从而实现485通信的收发,短接。DE=1, RE=0 → 发送模式,DE=0, RE=1 → 接收模式。当主机和多个从机进行信息交互时,①主机发送命令(DE=1,RE=0),指定目标设备地址(如 0x01),②目标从机响应(DE=0,RE=1),只有地址匹配的从机回复,其他从机保持静默,③主机切换至下一个设备,重复以上工作。RS485也能实现多主多从,多个主机工作时,要去检查A和B的电压差,如果发现其他主机工作,那么这个主机现在就不能发送数据,等待其他主机发送完后才能发送。
  RS232三根线,TX和RX和GND,工作时就把数据放到信号线上,没有什么设备地址这种操作,当多个设备并联时,如果几个设备同时工作,都会去控制TX和RX电压,就会出现问题,它不像RS485一样能够实现这个设备发送时候,其他设备就不能发送了,其次是不同设备地线电压不同(?)。
  i2c和spi也能实现一主多从,关键在意i2c能够传输设备地址,spi有片选信号线,当某个设备工作时候,就会拉低它这个设备对应的专属片选线。

3.2.3 帧

在这里插入图片描述  I2C这个写数据,先发设备地址,再发寄存器地址,最后发写的数据,这部分是一帧数据发送的,因为如果是三帧数据的话,第二步给寄存器地址都不知道往哪个设备去发。

http://www.dtcms.com/wzjs/11263.html

相关文章:

  • 互联网营销是干嘛的岳阳seo公司
  • 网页美工培训班seo站长工具查询
  • 动态网站制作视频教程域名查询138ip
  • 做苗木选择哪个网站搜索引擎营销
  • seo服务是什么新十条优化措施
  • 四川冠辰网站建设网络营销岗位有哪些
  • 铁岭网站制作引流用什么话术更吸引人
  • 深圳中高端网站建设怎么样重庆网站快速排名优化
  • 网站建设公司行业现状沈阳seo博客
  • 在国内做博彩网站代理百度科技有限公司
  • 最新新闻事件今天国内大事2022班级优化大师下载安装app
  • 开网站做外贸今日新闻最新消息50字
  • 网站建设项营销软文推广平台
  • 重庆九度设计优化大师win10下载
  • 阿里云做网站视频教程软文怎么写比较吸引人
  • 给人做网站多少钱网络优化大师app
  • 建站优化易下拉系统免费ip地址代理
  • 外贸网站运营推广整站seo外包
  • 如何使用mysql数据库做网站广州网站制作公司
  • 公司部门职责及配置关于进一步优化
  • 北京朝阳区二手房出售四川seo整站优化费用
  • 网站建设预计费用天津做网站的公司
  • 局域网内部如何做网站潍坊网站建设方案咨询
  • 衡水网络推广 衡水网站建设站内推广
  • 如何判断网站seo做的好坏百度免费推广有哪些方式
  • web网站开发总结百度网络优化
  • 房地产网站制作东莞百度快照优化排名
  • 一个域名解析多个网站国外媒体报道
  • 桂林旅游景点seo关键词排名优化技巧
  • 经典的网站设计工具企业网络推广网站